home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Demos / Donuts3D / donuts.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  100.3 KB  |  2,928 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Donuts.cpp
  3. //
  4. // Desc: DirectInput semantic mapper version of Donuts3D game
  5. //
  6. // Copyright (C) 1995-2001 Microsoft Corporation. All Rights Reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <windows.h>
  10. #include <windowsx.h>
  11. #include <basetsd.h>
  12. #include <cguid.h>
  13. #include <tchar.h>
  14. #include <mmsystem.h>
  15. #include <stdio.h>
  16. #include <math.h>
  17. #include <D3DX8.h>
  18. #include "D3DFile.h"
  19. #include "D3DFont.h"
  20. #include "D3DUtil.h"
  21. #include "DIUtil.h"
  22. #include "DMUtil.h"
  23. #include "DXUtil.h"
  24. #include "resource.h"
  25. #include "gamemenu.h"
  26. #include "donuts.h"
  27.  
  28.  
  29.  
  30.  
  31. //-----------------------------------------------------------------------------
  32. // Global access to the app (needed for the global WndProc())
  33. //-----------------------------------------------------------------------------
  34. CMyApplication*    g_pApp  = NULL;
  35. HINSTANCE          g_hInst = NULL;
  36.  
  37.  
  38.  
  39.  
  40. //-----------------------------------------------------------------------------
  41. // Name: WinMain()
  42. // Desc: Application entry point
  43. //-----------------------------------------------------------------------------
  44. int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow )
  45. {
  46.     CMyApplication app;
  47.  
  48.     g_hInst = hInstance;
  49.  
  50.     if( FAILED( app.Create( hInstance ) ) )
  51.         return 0;
  52.  
  53.     return app.Run();
  54. }
  55.  
  56.  
  57.  
  58.  
  59. //-----------------------------------------------------------------------------
  60. // Name: CMyApplication()
  61. // Desc: Constructor
  62. //-----------------------------------------------------------------------------
  63. CMyApplication::CMyApplication()
  64. {
  65.     g_pApp                  = this;
  66.     m_strAppName            = _T("Donuts3D");
  67.     m_hWndMain              = NULL;               
  68.     m_dwScreenWidth         = 800;   
  69.     m_dwScreenHeight        = 600;
  70.     m_bFullScreen           = FALSE; 
  71.     m_bIsActive             = FALSE; 
  72.     m_bDisplayReady         = FALSE; 
  73.     m_bMouseVisible         = FALSE;  
  74.     m_hSplashBitmap         = NULL;  
  75.     m_dwAppState            = APPSTATE_LOADSPLASH;              
  76.     m_dwLevel               = 0;     
  77.     m_dwScore               = 0;     
  78.     m_dwViewMode            = 2;     
  79.     m_fViewTransition       = 0.0f;  
  80.     m_bAnimatingViewChange  = FALSE; 
  81.     m_bFirstPersonView      = TRUE;  
  82.     m_fBulletRechargeTime   = 0.0f;  
  83.     m_dwBulletType          = 2;    
  84.     m_pDisplayList          = NULL;          
  85.     m_pShip                 = NULL;          
  86.     m_pd3dDevice            = NULL; 
  87.     m_pConfigSurface        = NULL; 
  88.     m_pViewportVB           = NULL;
  89.     m_pSpriteVB             = NULL;
  90.     m_pShipFileObject       = NULL; 
  91.     m_dwNumShipTypes        = 10L;
  92.     m_dwCurrentShipType     = 1;
  93.     m_pMusicManager         = NULL;  
  94.     m_pBeginLevelSound      = NULL;  
  95.     m_pEngineIdleSound      = NULL;
  96.     m_pEngineRevSound       = NULL;
  97.     m_pShieldBuzzSound      = NULL;
  98.     m_pShipExplodeSound     = NULL;
  99.     m_pFireBulletSound      = NULL;
  100.     m_pShipBounceSound      = NULL;
  101.     m_pDonutExplodeSound    = NULL;
  102.     m_pPyramidExplodeSound  = NULL;
  103.     m_pCubeExplodeSound     = NULL;
  104.     m_pSphereExplodeSound   = NULL;
  105.     m_pGameTexture1         = NULL; 
  106.     m_pGameTexture2         = NULL; 
  107.     m_pTerrain              = NULL;
  108.     m_pGameFont             = NULL;
  109.     m_pMenuFont             = NULL;
  110.     m_pMainMenu             = NULL;    
  111.     m_pQuitMenu             = NULL;
  112.     m_pCurrentMenu          = NULL;
  113.     m_pInputDeviceManager   = NULL;
  114.     m_bPaused               = FALSE;
  115.  
  116.     ZeroMemory( &m_UserInput, sizeof(m_UserInput) );
  117. }
  118.  
  119.  
  120.  
  121.  
  122. //-----------------------------------------------------------------------------
  123. // Name: Create()
  124. // Desc: Creates the window
  125. //-----------------------------------------------------------------------------
  126. HRESULT CMyApplication::Create( HINSTANCE hInstance )
  127. {
  128.     // Register the window class
  129.     WNDCLASS wndClass = { CS_DBLCLKS, StaticMsgProc, 0, 0, hInstance,
  130.                           LoadIcon( hInstance, MAKEINTRESOURCE(DONUTS_ICON) ),
  131.                           LoadCursor( NULL, IDC_ARROW ),
  132.                           (HBRUSH)GetStockObject( BLACK_BRUSH ),
  133.                           NULL, TEXT("DonutsClass") };
  134.     RegisterClass( &wndClass );
  135.  
  136.     // Create our main window
  137.     m_hWndMain = CreateWindowEx( 0, TEXT("DonutsClass"), TEXT("Donuts"),
  138.                                  WS_VISIBLE|WS_POPUP|WS_CAPTION|WS_SYSMENU,
  139.                                  0, 0, 640, 480, NULL, NULL,
  140.                                  hInstance, NULL );
  141.     if( NULL == m_hWndMain )
  142.         return E_FAIL;
  143.     UpdateWindow( m_hWndMain );
  144.  
  145.         // Create the game objects (display objects, sounds, input devices,
  146.         // menus, etc.)
  147.     if( FAILED( OneTimeSceneInit( m_hWndMain ) ) )
  148.     {
  149.         DestroyWindow( m_hWndMain );
  150.         return E_FAIL;
  151.     }
  152.  
  153.     return S_OK;
  154. }
  155.  
  156.  
  157.  
  158.  
  159. //-----------------------------------------------------------------------------
  160. // Name: Run()
  161. // Desc: Handles the message loop and calls FrameMove() and Render() when
  162. //       idle.
  163. //-----------------------------------------------------------------------------
  164. INT CMyApplication::Run()
  165. {
  166.     // Load keyboard accelerators
  167.     HACCEL hAccel = LoadAccelerators( NULL, MAKEINTRESOURCE(IDR_MAIN_ACCEL) );
  168.  
  169.     // Now we're ready to recieve and process Windows messages.
  170.     BOOL bGotMsg;
  171.     MSG  msg;
  172.     PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
  173.  
  174.     while( WM_QUIT != msg.message  )
  175.     {
  176.         // Use PeekMessage() if the app is active, so we can use idle time to
  177.         // render the scene. Else, use GetMessage() to avoid eating CPU time.
  178.         if( m_bIsActive )
  179.             bGotMsg = PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE );
  180.         else
  181.             bGotMsg = GetMessage( &msg, NULL, 0U, 0U );
  182.  
  183.         if( bGotMsg )
  184.         {
  185.             // Translate and dispatch the message
  186.             TranslateMessage( &msg );
  187.             DispatchMessage( &msg );
  188.         }
  189.         else
  190.         {
  191.             // Render a frame during idle time (no messages are waiting)
  192.             if( m_bDisplayReady )
  193.             {
  194.                 FrameMove();
  195.                 RenderFrame();
  196.             }
  197.         }
  198.     }
  199.  
  200.     return (int)msg.wParam;
  201. }
  202.  
  203.  
  204.  
  205.  
  206. //-----------------------------------------------------------------------------
  207. // Name: StaticMsgProc()
  208. // Desc: Static msg handler which passes messages to the application class.
  209. //-----------------------------------------------------------------------------
  210. LRESULT CALLBACK StaticMsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  211. {
  212.     return g_pApp->MsgProc( hWnd, uMsg, wParam, lParam );
  213. }
  214.  
  215.  
  216.  
  217.  
  218. //-----------------------------------------------------------------------------
  219. // Name: MsgProc()
  220. // Desc: Callback for all Windows messages
  221. //-----------------------------------------------------------------------------
  222. LRESULT CMyApplication::MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  223. {
  224.     switch( msg )
  225.     {
  226.         case WM_ACTIVATEAPP:
  227.             m_bIsActive = (BOOL)wParam;
  228.             m_bMouseVisible   = FALSE;
  229.  
  230.             if( m_bIsActive )
  231.             {
  232.                 DXUtil_Timer( TIMER_START );
  233.             }
  234.             else
  235.             {
  236.                 DXUtil_Timer( TIMER_STOP );
  237.             }
  238.             break;
  239.  
  240.         case WM_GETMINMAXINFO:
  241.             ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 320;
  242.             ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 200;
  243.             break;
  244.  
  245.         case WM_SETCURSOR:
  246.             if( !m_bMouseVisible && m_dwAppState!=APPSTATE_DISPLAYSPLASH )
  247.                 SetCursor( NULL );
  248.             else
  249.                 SetCursor( LoadCursor( NULL, IDC_ARROW ) );
  250.             return TRUE;
  251.  
  252.         case WM_SYSCOMMAND:
  253.             // Prevent moving/sizing and power loss
  254.             switch( wParam )
  255.             {
  256.                 case SC_MOVE:
  257.                 case SC_SIZE:
  258.                 case SC_MAXIMIZE:
  259.                 case SC_KEYMENU:
  260.                 case SC_MONITORPOWER:
  261.                         return 1;
  262.             }
  263.             break;
  264.  
  265.                 case WM_SYSKEYDOWN:
  266.             // Handle Alt+Enter to do mode-switching
  267.             if( VK_RETURN == wParam )
  268.             {
  269.                 SwitchDisplayModes( !m_bFullScreen, m_dwScreenWidth,
  270.                                     m_dwScreenHeight );
  271.             }
  272.             break;
  273.  
  274.         case WM_KEYDOWN:
  275.             // Move from splash screen when user presses a key
  276.             if( m_dwAppState == APPSTATE_DISPLAYSPLASH )
  277.             {
  278.                 if( wParam==VK_ESCAPE )
  279.                 {
  280.                     // Escape keys exits the app
  281.                     PostMessage( hWnd, WM_CLOSE, 0, 0 );
  282.                     m_bDisplayReady = FALSE;
  283.                 }
  284.                 else
  285.                 {
  286.                     // Get rid of splash bitmap
  287.                     DeleteObject( m_hSplashBitmap );
  288.  
  289.                     // Advance to the first level
  290.                     m_dwAppState = APPSTATE_BEGINLEVELSCREEN;
  291.                     DXUtil_Timer( TIMER_START );
  292.                     AdvanceLevel();
  293.                 }
  294.             }
  295.             return 0;
  296.  
  297.         case WM_PAINT:
  298.             if( m_dwAppState == APPSTATE_DISPLAYSPLASH )
  299.             {
  300.                 BITMAP bmp;
  301.                 RECT rc;
  302.                 GetClientRect( m_hWndMain, &rc );
  303.  
  304.                 // Display the splash bitmap in the window
  305.                 HDC hDCWindow = GetDC( m_hWndMain );
  306.                 HDC hDCImage  = CreateCompatibleDC( NULL );
  307.                 SelectObject( hDCImage, m_hSplashBitmap );
  308.                 GetObject( m_hSplashBitmap, sizeof(bmp), &bmp );
  309.                 StretchBlt( hDCWindow, 0, 0, rc.right, rc.bottom,
  310.                             hDCImage, 0, 0,
  311.                             bmp.bmWidth, bmp.bmHeight, SRCCOPY );
  312.                 DeleteDC( hDCImage );
  313.                 ReleaseDC( m_hWndMain, hDCWindow );
  314.             }
  315.             else
  316.             {
  317.                 if( m_bDisplayReady )
  318.                 {
  319.                     DrawDisplayList();
  320.                     ShowFrame();
  321.                 }
  322.             }
  323.             break;
  324.  
  325.         case WM_DESTROY:
  326.             FinalCleanup();
  327.             PostQuitMessage( 0 );
  328.             m_bDisplayReady = FALSE;
  329.             break;
  330.     }
  331.  
  332.     return DefWindowProc( hWnd, msg, wParam, lParam );
  333. }
  334.  
  335.  
  336.  
  337.  
  338. //-----------------------------------------------------------------------------
  339. // Name: OneTimeSceneInit()
  340. // Desc:
  341. //-----------------------------------------------------------------------------
  342. HRESULT CMyApplication::OneTimeSceneInit( HWND hWnd )
  343. {
  344.     HRESULT hr;
  345.  
  346.     // Initialize the DirectInput stuff
  347.     if( FAILED( hr = CreateInputObjects( hWnd ) ) )
  348.         return hr;
  349.  
  350.     // Initialize the DirectSound stuff. Note: if this call fails, we can
  351.         // continue with no sound.
  352.     CreateSoundObjects( hWnd );
  353.  
  354.     // Create the display objects
  355.     if( FAILED( hr = CreateDisplayObjects( hWnd ) ) )
  356.         return hr;
  357.  
  358.     // Add a ship to the displaylist
  359.     m_pShip = new CShip( D3DXVECTOR3(0.0f,0.0f,0.0f) );
  360.     m_pDisplayList = m_pShip;
  361.  
  362.     // Construct the game menus
  363.     ConstructMenus();
  364.  
  365.     // Initial program state is to display the splash screen
  366.     m_dwAppState = APPSTATE_LOADSPLASH;
  367.  
  368.     return S_OK;
  369. }
  370.  
  371.  
  372.  
  373.  
  374. //-----------------------------------------------------------------------------
  375. // Name: FinalCleanup()
  376. // Desc:
  377. //-----------------------------------------------------------------------------
  378. VOID CMyApplication::FinalCleanup()
  379. {
  380.     DestroyDisplayObjects();
  381.     DestroySoundObjects();
  382.     DestroyInputObjects();
  383.     DestroyMenus();
  384. }
  385.  
  386.  
  387.  
  388.  
  389. //-----------------------------------------------------------------------------
  390. // Name: AdvanceLevel()
  391. // Desc:
  392. //-----------------------------------------------------------------------------
  393. VOID CMyApplication::AdvanceLevel()
  394. {
  395.     // Up the level
  396.     m_dwLevel++;
  397.  
  398.     srand( timeGetTime() );
  399.  
  400.     // Clear any stray objects (anything but the ship) out of the display list
  401.     while( m_pShip->pNext )
  402.     {
  403.         DeleteFromList( m_pShip->pNext );
  404.     }
  405.  
  406.     // Create donuts for the new level
  407.     for( WORD i=0; i<(2*m_dwLevel+3); i++ )
  408.     {
  409.         D3DVECTOR vPosition = 3.0f * D3DXVECTOR3( rnd(), rnd(), 0.0f );
  410.         D3DVECTOR vVelocity = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  411.  
  412.         AddToList( new CDonut( vPosition, vVelocity ) );
  413.     }
  414.  
  415.     // Delay for 2 seconds before displaying ship
  416.     m_pShip->vPos       = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  417.     m_pShip->vVel       = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  418.     m_pShip->bVisible   = FALSE;
  419.     m_pShip->bExploded  = FALSE;
  420.     m_pShip->fShowDelay = 2.0f;
  421.  
  422.     // Stop engine sounds
  423.     StopSound( m_pEngineIdleSound );
  424.     StopSound( m_pEngineRevSound );
  425. }
  426.  
  427.  
  428.  
  429.  
  430. //-----------------------------------------------------------------------------
  431. // Name: DisplayObject()
  432. // Desc:
  433. //-----------------------------------------------------------------------------
  434. DisplayObject::DisplayObject( DWORD type, D3DVECTOR p, D3DVECTOR v )
  435. {
  436.     // Set object attributes
  437.     pNext    = NULL;
  438.     pPrev    = NULL;
  439.     bVisible = TRUE;
  440.     dwType   = type;
  441.     vPos     = p;
  442.     vVel     = v;
  443. }
  444.  
  445.  
  446.  
  447.  
  448. //-----------------------------------------------------------------------------
  449. // Name: C3DSprite()
  450. // Desc:
  451. //-----------------------------------------------------------------------------
  452. C3DSprite::C3DSprite( DWORD type, D3DVECTOR p, D3DVECTOR v )
  453.           :DisplayObject( type, p, v )
  454. {
  455.     dwColor = 0xffffffff;
  456. }
  457.  
  458.  
  459.  
  460.  
  461. //-----------------------------------------------------------------------------
  462. // Name: CDonut()
  463. // Desc:
  464. //-----------------------------------------------------------------------------
  465. CDonut::CDonut( D3DVECTOR p, D3DVECTOR v )
  466.        :C3DSprite( OBJ_DONUT, p, v )
  467. {
  468.     // Set object attributes
  469.     dwTextureWidth   = DONUT_WIDTH;
  470.     dwTextureHeight  = DONUT_HEIGHT;
  471.     dwTextureOffsetX = 0;
  472.     dwTextureOffsetY = 0;
  473.  
  474.     fSize           = dwTextureWidth / 256.0f;
  475.     vVel            += 0.5f * D3DXVECTOR3( rnd(), rnd(), 0.0f );
  476.  
  477.     delay           = rnd( 3.0f, 12.0f );
  478.     dwFramesPerLine = 8;
  479.     frame           = rnd( 0.0f, 30.0f );
  480.     fMaxFrame       = NUM_DONUT_FRAMES;
  481. }
  482.  
  483.  
  484.  
  485.  
  486. //-----------------------------------------------------------------------------
  487. // Name: CPyramid()
  488. // Desc:
  489. //-----------------------------------------------------------------------------
  490. CPyramid::CPyramid( D3DVECTOR p, D3DVECTOR v )
  491.          :C3DSprite( OBJ_PYRAMID, p, v )
  492. {
  493.     // Set object attributes
  494.     dwTextureWidth   = PYRAMID_WIDTH;
  495.     dwTextureHeight  = PYRAMID_HEIGHT;
  496.     dwTextureOffsetX = 0;
  497.     dwTextureOffsetY = 0;
  498.  
  499.     fSize           = dwTextureWidth / 256.0f;
  500.     vVel            += 0.5f * D3DXVECTOR3( rnd(), rnd(), 0.0f );
  501.  
  502.     delay           = rnd( 12.0f, 40.0f );
  503.     dwFramesPerLine = 8;
  504.     frame           = rnd( 0.0f, 30.0f );
  505.     fMaxFrame       = NUM_PYRAMID_FRAMES;
  506.  
  507. }
  508.  
  509.  
  510.  
  511.  
  512. //-----------------------------------------------------------------------------
  513. // Name: CSphere()
  514. // Desc:
  515. //-----------------------------------------------------------------------------
  516. CSphere::CSphere( D3DVECTOR p, D3DVECTOR v )
  517.         :C3DSprite( OBJ_SPHERE, p, v )
  518. {
  519.     // Set object attributes
  520.     dwTextureWidth   = SPHERE_WIDTH;
  521.     dwTextureHeight  = SPHERE_HEIGHT;
  522.     dwTextureOffsetX = 0;
  523.     dwTextureOffsetY = 128;
  524.  
  525.     fSize           = dwTextureWidth / 256.0f;
  526.     vVel            += 0.5f * D3DXVECTOR3( rnd(), rnd(), 0.0f );
  527.  
  528.     delay           = rnd( 60.0f, 80.0f );
  529.     dwFramesPerLine = 16;
  530.     frame           = rnd( 0.0f, 30.0f );
  531.     fMaxFrame       = NUM_SPHERE_FRAMES;
  532. }
  533.  
  534.  
  535.  
  536.  
  537.  
  538. //-----------------------------------------------------------------------------
  539. // Name: CCube()
  540. // Desc:
  541. //-----------------------------------------------------------------------------
  542. CCube::CCube( D3DVECTOR p, D3DVECTOR v )
  543.       :C3DSprite( OBJ_CUBE, p, v )
  544. {
  545.     // Set object attributes
  546.     dwTextureWidth   = CUBE_WIDTH;
  547.     dwTextureHeight  = CUBE_HEIGHT;
  548.     dwTextureOffsetX = 0;
  549.     dwTextureOffsetY = 176;
  550.  
  551.     fSize           = dwTextureWidth / 256.0f;
  552.     vVel            += 0.5f * D3DXVECTOR3( rnd(), rnd(), 0.0f );
  553.  
  554.     delay           = rnd( 32.0f, 80.0f );
  555.     dwFramesPerLine = 16;
  556.     frame           = rnd( 0.0f, 30.0f );
  557.     fMaxFrame       = NUM_CUBE_FRAMES;
  558. }
  559.  
  560.  
  561.  
  562.  
  563. //-----------------------------------------------------------------------------
  564. // Name: CCloud()
  565. // Desc:
  566. //-----------------------------------------------------------------------------
  567. CCloud::CCloud( D3DVECTOR p, D3DVECTOR v )
  568.        :C3DSprite( OBJ_CLOUD, p, v )
  569. {
  570.     // Set object attributes
  571.     dwTextureWidth   = CLOUD_WIDTH;
  572.     dwTextureHeight  = CLOUD_WIDTH;
  573.     dwTextureOffsetX = 224;
  574.     dwTextureOffsetY = 224;
  575.  
  576.     fSize           = dwTextureWidth / 256.0f;
  577.     delay           = rnd( 1.0f, 3.0f );
  578.     dwFramesPerLine = 1;
  579.     frame           = 0.0f;
  580.     fMaxFrame       = 1;
  581. }
  582.  
  583.  
  584.  
  585.  
  586. //-----------------------------------------------------------------------------
  587. // Name: CBullet()
  588. // Desc:
  589. //-----------------------------------------------------------------------------
  590. CBullet::CBullet( D3DVECTOR p, D3DVECTOR v, DWORD dwCType )
  591.         :C3DSprite( OBJ_BULLET, p, v )
  592. {
  593.     // Set object attributes
  594.     dwTextureWidth   = CLOUD_WIDTH;
  595.     dwTextureHeight  = CLOUD_HEIGHT;
  596.     dwTextureOffsetX = 224;
  597.     dwTextureOffsetY = 224;
  598.  
  599.     if( dwCType == 0 )
  600.         dwColor = 0xff2020ff;
  601.     if( dwCType == 1 )
  602.         dwColor = 0xff208020;
  603.     if( dwCType == 2 )
  604.         dwColor = 0xff208080;
  605.     if( dwCType == 3 )
  606.         dwColor = 0xff802020;
  607.  
  608.     fSize           = 4 / 256.0f;
  609.     fMaxFrame       = NUM_BULLET_FRAMES;
  610.  
  611.     delay           = 1000.0f;
  612.     dwFramesPerLine = 1;
  613.     frame           = 0.0f;
  614. }
  615.  
  616.  
  617.  
  618.  
  619. //-----------------------------------------------------------------------------
  620. // Name: CShip()
  621. // Desc:
  622. //-----------------------------------------------------------------------------
  623. CShip::CShip( D3DVECTOR p )
  624.       :DisplayObject( OBJ_SHIP, p, D3DXVECTOR3(0,0,0) )
  625. {
  626.     fSize           = 10.0f / 256.0f;
  627.     bExploded       = FALSE;
  628.     fShowDelay      = 0.0f;
  629.  
  630.     fRoll           = 0.0f;
  631.     fAngle          = 0.0f;
  632. }
  633.  
  634.  
  635.  
  636.  
  637. //-----------------------------------------------------------------------------
  638. // Name: AddToList()
  639. // Desc:
  640. //-----------------------------------------------------------------------------
  641. VOID CMyApplication::AddToList( DisplayObject* pObject )
  642. {
  643.     pObject->pNext = m_pDisplayList->pNext;
  644.     pObject->pPrev = m_pDisplayList;
  645.  
  646.     if( m_pDisplayList->pNext )
  647.         m_pDisplayList->pNext->pPrev = pObject;
  648.     m_pDisplayList->pNext = pObject;
  649. }
  650.  
  651.  
  652.  
  653.  
  654. //-----------------------------------------------------------------------------
  655. // Name: IsDisplayListEmpty()
  656. // Desc:
  657. //-----------------------------------------------------------------------------
  658. BOOL CMyApplication::IsDisplayListEmpty()
  659. {
  660.     DisplayObject* pObject = m_pDisplayList->pNext;
  661.  
  662.     while( pObject )
  663.     {
  664.         if( pObject->dwType != OBJ_BULLET )
  665.             return FALSE;
  666.  
  667.         pObject = pObject->pNext;
  668.     }
  669.  
  670.     return TRUE;
  671. }
  672.  
  673.  
  674.  
  675.  
  676. //-----------------------------------------------------------------------------
  677. // Name: LoadTerrainModel()
  678. // Desc: Loads the 3D geometry for the terrain
  679. //-----------------------------------------------------------------------------
  680. HRESULT CMyApplication::LoadTerrainModel()
  681. {
  682.     LPDIRECT3DVERTEXBUFFER8 pVB;
  683.     DWORD        dwNumVertices;
  684.     MODELVERTEX* pVertices;
  685.  
  686.     // Delete old object
  687.     SAFE_DELETE( m_pTerrain );
  688.  
  689.     // Create new object
  690.     m_pTerrain = new CD3DMesh();
  691.     if( FAILED( m_pTerrain->Create( m_pd3dDevice, _T("SeaFloor.x") ) ) )
  692.         return E_FAIL;
  693.  
  694.     // Set the FVF to a reasonable type
  695.     m_pTerrain->SetFVF( m_pd3dDevice, D3DFVF_MODELVERTEX );
  696.  
  697.     // Gain access to the model's vertices
  698.     m_pTerrain->GetSysMemMesh()->GetVertexBuffer( &pVB );
  699.     dwNumVertices = m_pTerrain->GetSysMemMesh()->GetNumVertices();
  700.     pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );
  701.  
  702.     for( DWORD i=0; i<dwNumVertices; i++ )
  703.     {
  704.         pVertices[i].p.x *= 0.1f;
  705.         pVertices[i].p.z *= 0.1f;
  706.         pVertices[i].p.y = HeightField( pVertices[i].p.x, pVertices[i].p.z );
  707.     }
  708.  
  709.     // Done with the vertex buffer
  710.     pVB->Unlock();
  711.     pVB->Release();
  712.  
  713.     return S_OK;
  714. }
  715.  
  716.  
  717.  
  718.  
  719. //-----------------------------------------------------------------------------
  720. // Name: LoadShipModel()
  721. // Desc: Loads the 3D geometry for the player's ship
  722. //-----------------------------------------------------------------------------
  723. HRESULT CMyApplication::LoadShipModel()
  724. {
  725.     LPDIRECT3DVERTEXBUFFER8 pVB;
  726.     DWORD        dwNumVertices;
  727.     MODELVERTEX* pVertices;
  728.     D3DXVECTOR3  vCenter;
  729.     FLOAT        fRadius;
  730.  
  731.     // Delete old object
  732.     SAFE_DELETE( m_pShipFileObject );
  733.  
  734.     // Create new object
  735.     m_pShipFileObject = new CD3DMesh();
  736.     if( FAILED( m_pShipFileObject->Create( m_pd3dDevice,
  737.                                            g_strShipFiles[m_dwCurrentShipType] ) ) )
  738.         return E_FAIL;
  739.  
  740.     // Set the FVF to a reasonable type
  741.     m_pShipFileObject->SetFVF( m_pd3dDevice, D3DFVF_MODELVERTEX );
  742.  
  743.     // Gain access to the model's vertices
  744.     m_pShipFileObject->GetSysMemMesh()->GetVertexBuffer( &pVB );
  745.     dwNumVertices = m_pShipFileObject->GetSysMemMesh()->GetNumVertices();
  746.     pVB->Lock( 0, 0, (BYTE**)&pVertices, 0 );
  747.  
  748.     // Scale the new object to a standard size  
  749.     D3DXComputeBoundingSphere( pVertices, dwNumVertices,
  750.                                D3DFVF_MODELVERTEX, &vCenter, &fRadius );
  751.     for( DWORD i=0; i<dwNumVertices; i++ )
  752.     {
  753.         pVertices[i].p /= 12*fRadius;
  754.     }
  755.  
  756.     // Done with the vertex buffer
  757.     pVB->Unlock();
  758.     pVB->Release();
  759.  
  760.     return S_OK;
  761. }
  762.  
  763.  
  764.  
  765.  
  766. //-----------------------------------------------------------------------------
  767. // Name: SwitchModel()
  768. // Desc:
  769. //-----------------------------------------------------------------------------
  770. HRESULT CMyApplication::SwitchModel()
  771. {
  772.     // Select next model
  773.     m_dwCurrentShipType++;
  774.     if( m_dwCurrentShipType >= m_dwNumShipTypes )
  775.         m_dwCurrentShipType = 0L;
  776.  
  777.     // Create new object
  778.     if( SUCCEEDED( LoadShipModel() ) )
  779.     {
  780.         // Initialize the new object's device dependent objects
  781.         if( SUCCEEDED( m_pShipFileObject->RestoreDeviceObjects( m_pd3dDevice ) ) )
  782.             return S_OK;
  783.     }
  784.  
  785.     // Return with a fatal error
  786.     PostMessage( m_hWndMain, WM_CLOSE, 0, 0 );
  787.     return E_FAIL;
  788. }
  789.  
  790.  
  791.  
  792.  
  793. //-----------------------------------------------------------------------------
  794. // Name: FrameMove()
  795. // Desc:
  796. //-----------------------------------------------------------------------------
  797. HRESULT CMyApplication::FrameMove()
  798. {
  799.     switch( m_dwAppState )
  800.     {
  801.         case APPSTATE_LOADSPLASH:
  802.             // Set the app state to displaying splash
  803.             m_dwAppState = APPSTATE_DISPLAYSPLASH;
  804.  
  805.             // Draw the splash bitmap
  806.             m_hSplashBitmap = (HBITMAP)LoadImage( GetModuleHandle( NULL ),
  807.                                                   TEXT("SPLASH"), IMAGE_BITMAP,
  808.                                                   0, 0, LR_CREATEDIBSECTION );
  809.             SendMessage( m_hWndMain, WM_PAINT, 0, 0 );
  810.             break;
  811.  
  812.         case APPSTATE_ACTIVE:
  813.             UpdateDisplayList();
  814.             CheckForHits();
  815.  
  816.             if( IsDisplayListEmpty() )
  817.             {
  818.                 AdvanceLevel();
  819.                 m_dwAppState = APPSTATE_BEGINLEVELSCREEN;
  820.             }
  821.             break;
  822.  
  823.         case APPSTATE_BEGINLEVELSCREEN:
  824.             PlaySound( m_pBeginLevelSound );
  825.             DXUtil_Timer( TIMER_RESET );
  826.             m_dwAppState = APPSTATE_DISPLAYLEVELSCREEN;
  827.             break;
  828.  
  829.         case APPSTATE_DISPLAYLEVELSCREEN:
  830.             // Only show the Level intro screen for 3 seconds
  831.  
  832.             if( DXUtil_Timer( TIMER_GETAPPTIME ) > 3.0f )
  833.             {
  834.                 m_dwAppState = APPSTATE_ACTIVE;
  835.             }
  836.             break;
  837.     }
  838.  
  839.     return S_OK;
  840. }
  841.  
  842.  
  843.  
  844.  
  845. //-----------------------------------------------------------------------------
  846. // Name: RenderFrame()
  847. // Desc:
  848. //-----------------------------------------------------------------------------
  849. HRESULT CMyApplication::RenderFrame()
  850. {
  851.     // Test cooperative level
  852.     HRESULT hr;
  853.  
  854.     // Test the cooperative level to see if it's okay to render
  855.     if( FAILED( hr = m_pd3dDevice->TestCooperativeLevel() ) )
  856.     {
  857.         // If the device was lost, do not render until we get it back
  858.         if( D3DERR_DEVICELOST == hr )
  859.             return S_OK;
  860.  
  861.         // Check if the device needs to be resized.
  862.         if( D3DERR_DEVICENOTRESET == hr )
  863.         {
  864.             m_bDisplayReady = FALSE;
  865.  
  866.             InvalidateDisplayObjects();
  867.  
  868.             // Resize the device
  869.             if( SUCCEEDED( m_pd3dDevice->Reset( &m_d3dpp ) ) )
  870.             {
  871.                 // Initialize the app's device-dependent objects
  872.                 if( SUCCEEDED( RestoreDisplayObjects() ) )
  873.                 {
  874.                     m_bDisplayReady = TRUE;
  875.                     return S_OK;
  876.                 }
  877.             }
  878.  
  879.             PostMessage( m_hWndMain, WM_CLOSE, 0, 0 );
  880.         }
  881.         return hr;
  882.     }
  883.  
  884.     // Render the scene based on current state of the app
  885.     switch( m_dwAppState )
  886.     {
  887.         case APPSTATE_LOADSPLASH:
  888.             // Nothing to render while loading the splash screen
  889.             break;
  890.  
  891.         case APPSTATE_DISPLAYSPLASH:
  892.             // Rendering of the splash screen is handled by WM_PAINT
  893.             break;
  894.  
  895.         case APPSTATE_BEGINLEVELSCREEN:
  896.             // Nothing to render while starting sound to advance a level
  897.             break;
  898.  
  899.         case APPSTATE_DISPLAYLEVELSCREEN:
  900.             DisplayLevelIntroScreen( m_dwLevel );
  901.             ShowFrame();
  902.             break;
  903.  
  904.         case APPSTATE_ACTIVE:
  905.             DrawDisplayList();
  906.             ShowFrame();
  907.             break;
  908.     }
  909.  
  910.     return S_OK;
  911. }
  912.  
  913.  
  914.  
  915.  
  916. //-----------------------------------------------------------------------------
  917. // Name: DarkenScene()
  918. // Desc:
  919. //-----------------------------------------------------------------------------
  920. VOID CMyApplication::DarkenScene( FLOAT fAmount )
  921. {
  922.     if( m_pd3dDevice==NULL )
  923.         return;
  924.  
  925.     // Setup a dark square to cover the scene
  926.     DWORD dwAlpha = (fAmount<1.0f) ? ((DWORD)(255*fAmount))<<24L : 0xff000000;
  927.     SCREENVERTEX* v;
  928.     m_pViewportVB->Lock( 0, 0, (BYTE**)&v, 0 );
  929.     v[0].color = v[1].color = v[2].color = v[3].color = dwAlpha;
  930.     m_pViewportVB->Unlock();
  931.  
  932.     // Set renderstates
  933.     m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  934.     m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
  935.     m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  936.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,   FALSE );
  937.     m_pd3dDevice->SetTexture( 0, NULL );
  938.  
  939.     // Draw a big, gray square
  940.     m_pd3dDevice->SetVertexShader( D3DFVF_SCREENVERTEX );
  941.     m_pd3dDevice->SetStreamSource( 0, m_pViewportVB, sizeof(SCREENVERTEX) );
  942.     m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,0, 2 );
  943.  
  944.     // Restore states
  945.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  946.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  947.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  948.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  949.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
  950.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );
  951. }
  952.  
  953.  
  954.  
  955.  
  956. //-----------------------------------------------------------------------------
  957. // Name:
  958. // Desc:
  959. //-----------------------------------------------------------------------------
  960. VOID CMyApplication::RenderFieryText( CD3DFont* pFont, TCHAR* strText )
  961. {
  962.     if( NULL==pFont || NULL==strText )
  963.         return;
  964.  
  965.     // Render the fiery portion of the text
  966.     for( DWORD i=0; i<20; i++ )
  967.     {
  968.         FLOAT x = -0.5f;
  969.         FLOAT y =  1.8f;
  970.  
  971.         FLOAT v1 = rnd(0.0f, 1.0f);
  972.         FLOAT red1 = v1*v1*v1;
  973.         FLOAT grn1 = v1*v1;
  974.         FLOAT blu1 = v1;
  975.  
  976.  
  977.         FLOAT a1 = rnd(0.0f, 2*D3DX_PI);
  978.         FLOAT r1 = v1 * 0.05f;
  979.  
  980.         x += r1*sinf(a1);
  981.         y += r1*cosf(a1);
  982.  
  983.         if( cosf(a1) < 0.0f )
  984.             y -= 2*r1*cosf(a1)*cosf(a1);
  985.  
  986.         DWORD r = (CHAR)((1.0f-red1)*256.0f);
  987.         DWORD g = (CHAR)((1.0f-grn1)*256.0f);
  988.         DWORD b = (CHAR)((1.0f-blu1)*256.0f);
  989.         DWORD a = (CHAR)255;
  990.         DWORD dwColor = (a<<24) + (r<<16) + (g<<8) + b;
  991.  
  992.         m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_ONE );
  993.         m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  994.  
  995.         pFont->DrawTextScaled( x, y, 0.9f, 0.25f, 0.25f, dwColor, strText, D3DFONT_FILTERED );
  996.     }
  997.  
  998.     // Render the plain, black portion of the text
  999.     m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
  1000.     m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  1001.     FLOAT x = -0.5f;
  1002.     FLOAT y =  1.8f;
  1003.     pFont->DrawTextScaled( x, y, 0.9f, 0.25f, 0.25f, 0xff000000, strText, D3DFONT_FILTERED );
  1004. }
  1005.  
  1006.  
  1007.  
  1008.  
  1009. //-----------------------------------------------------------------------------
  1010. // Name: DisplayLevelIntroScreen()
  1011. // Desc:
  1012. //-----------------------------------------------------------------------------
  1013. VOID CMyApplication::DisplayLevelIntroScreen( DWORD dwLevel )
  1014. {
  1015.     if( m_pd3dDevice==NULL )
  1016.         return;
  1017.  
  1018.     // Begin the scene
  1019.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  1020.     {
  1021.         // Erase the screen
  1022.         m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0L, 1.0f, 0L );
  1023.  
  1024.         TCHAR strLevel[80];
  1025.         _stprintf( strLevel, _T("Level %ld"), dwLevel );
  1026.         RenderFieryText( m_pGameFont, strLevel );
  1027.  
  1028.         DarkenScene( 1.0f - sinf(D3DX_PI*DXUtil_Timer( TIMER_GETAPPTIME )/3.0f) );
  1029.  
  1030.         // End the scene
  1031.         m_pd3dDevice->EndScene();
  1032.     }
  1033. }
  1034.  
  1035.  
  1036.  
  1037.  
  1038. //-----------------------------------------------------------------------------
  1039. // Name: UpdateDisplayList()
  1040. // Desc:
  1041. //-----------------------------------------------------------------------------
  1042. VOID CMyApplication::UpdateDisplayList()
  1043. {
  1044.     DisplayObject* pObject;
  1045.  
  1046.     // Get the time lapsed since the last frame
  1047.     FLOAT fTimeLapsed = DXUtil_Timer( TIMER_GETELAPSEDTIME );
  1048.  
  1049.     // Read input from the joystick/keyboard/etc
  1050.     UpdateInput( &m_UserInput );
  1051.  
  1052.     // Check for game menu condition
  1053.     if( m_pCurrentMenu )
  1054.     {
  1055.         UpdateMenus();
  1056.         return;
  1057.     }
  1058.  
  1059.     if( m_bPaused )
  1060.         return;
  1061.  
  1062.     if( m_pShip->fShowDelay > 0.0f )
  1063.     {
  1064.         m_pShip->fShowDelay -= fTimeLapsed;
  1065.  
  1066.         if( m_pShip->fShowDelay <= 0.0f )
  1067.         {
  1068.             m_pShip->vVel       = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  1069.             m_pShip->fShowDelay = 0.0f;
  1070.             m_pShip->bVisible   = TRUE;
  1071.             m_pShip->bExploded  = FALSE;
  1072.         }
  1073.     }
  1074.  
  1075.     // Update the ship
  1076.     if( m_pShip->bVisible )
  1077.     {
  1078.         m_pShip->vPos += m_pShip->vVel * fTimeLapsed;
  1079.     }
  1080.  
  1081.     // Apply banking motion
  1082.     m_pShip->fRoll += m_UserInput.fAxisRotateLR * 1.0f * fTimeLapsed;
  1083.     if( m_pShip->fRoll > 0.5f )
  1084.         m_pShip->fRoll = 0.5f;
  1085.     if( m_pShip->fRoll < -0.5f )
  1086.         m_pShip->fRoll = -0.5f;
  1087.  
  1088.     m_pShip->fAngle += 5 * m_pShip->fRoll * fTimeLapsed;
  1089.  
  1090.     if( m_UserInput.fAxisRotateLR < 0.2f && m_UserInput.fAxisRotateLR > -0.2f )
  1091.     {
  1092.         m_pShip->fRoll *= 0.95f;
  1093.     }
  1094.  
  1095.     // Slow the ship down
  1096.     m_pShip->vVel.x *= 0.97f;
  1097.     m_pShip->vVel.y *= 0.97f;
  1098.  
  1099.     // Apply thrust
  1100.     m_pShip->vVel.x +=  sinf( m_pShip->fAngle ) * m_UserInput.fAxisMoveUD * 5.0f * fTimeLapsed;
  1101.     m_pShip->vVel.y += -cosf( m_pShip->fAngle ) * m_UserInput.fAxisMoveUD * 5.0f * fTimeLapsed;
  1102.  
  1103.     // Play thrusting sounds
  1104.     {
  1105.         static bPlayingEngineRevSound = FALSE;
  1106.  
  1107.         if( m_UserInput.fAxisMoveUD > 0.5f )
  1108.         {
  1109.             if( FALSE == bPlayingEngineRevSound )
  1110.             {
  1111.                 bPlayingEngineRevSound = TRUE;
  1112.             }
  1113.         }
  1114.         else
  1115.         {
  1116.             if( TRUE == bPlayingEngineRevSound )
  1117.             {
  1118.                 StopSound( m_pEngineRevSound );
  1119.                 bPlayingEngineRevSound = FALSE;
  1120.             }
  1121.         }
  1122.     }
  1123.  
  1124.     m_fBulletRechargeTime -= fTimeLapsed;
  1125.  
  1126.      // Fire a bullet
  1127.     if( m_UserInput.bButtonFireWeapons && m_fBulletRechargeTime <= 0.0f )
  1128.     {
  1129.         // Ship must be visible and have no shields on to fire
  1130.         if( m_pShip->bVisible )
  1131.         {
  1132.             // Bullets cost one score point
  1133.             if( m_dwScore )
  1134.                 m_dwScore--;
  1135.  
  1136.             // Play the "fire" effects
  1137.             PlaySound( m_pFireBulletSound );
  1138.  
  1139.             // Add a bullet to the display list
  1140.             if( m_dwBulletType == 0 )
  1141.             {
  1142.                 D3DXVECTOR3 vDir = D3DXVECTOR3( sinf( m_pShip->fAngle ), -cosf( m_pShip->fAngle ), 0.0f );
  1143.  
  1144.                 AddToList( new CBullet( m_pShip->vPos, m_pShip->vVel + 2*vDir, 0 ) );
  1145.                 m_fBulletRechargeTime = 0.05f;
  1146.             }
  1147.             else if( m_dwBulletType == 1 )
  1148.             {
  1149.                 D3DXVECTOR3 vOffset = 0.02f * D3DXVECTOR3( cosf(m_pShip->fAngle), sinf(m_pShip->fAngle), 0.0f );
  1150.                 D3DXVECTOR3 vDir = D3DXVECTOR3( sinf( m_pShip->fAngle ), -cosf( m_pShip->fAngle ), 0.0f );
  1151.  
  1152.                 AddToList( new CBullet( m_pShip->vPos + vOffset, m_pShip->vVel + 2*vDir, 1 ) );
  1153.                 AddToList( new CBullet( m_pShip->vPos - vOffset, m_pShip->vVel + 2*vDir, 1 ) );
  1154.                 m_fBulletRechargeTime = 0.10f;
  1155.             }
  1156.             else if( m_dwBulletType == 2 )
  1157.             {
  1158.                 FLOAT fBulletAngle = m_pShip->fAngle + 0.2f*rnd();
  1159.                 D3DXVECTOR3 vDir = D3DXVECTOR3( sinf(fBulletAngle), -cosf(fBulletAngle), 0.0f );
  1160.  
  1161.                 AddToList( new CBullet( m_pShip->vPos, m_pShip->vVel + 2*vDir, 2 ) );
  1162.                 m_fBulletRechargeTime = 0.01f;
  1163.             }
  1164.             else
  1165.             {
  1166.                 for( DWORD i=0; i<50; i++ )
  1167.                 {
  1168.                     FLOAT fBulletAngle = m_pShip->fAngle + D3DX_PI*rnd();
  1169.                     D3DXVECTOR3 vDir = D3DXVECTOR3( sinf(fBulletAngle), -cosf(fBulletAngle), 0.0f );
  1170.  
  1171.                     AddToList( new CBullet( m_pShip->vPos, 2*vDir, 3 ) );
  1172.                 }
  1173.  
  1174.                 m_fBulletRechargeTime = 1.0f;
  1175.             }
  1176.         }
  1177.     }
  1178.  
  1179.     // Keep ship in bounds
  1180.     if( m_pShip->vPos.x < -5.0f || m_pShip->vPos.x > +5.0f ||
  1181.         m_pShip->vPos.y < -5.0f || m_pShip->vPos.y > +5.0f )
  1182.     {
  1183.          D3DXVec3Normalize( &m_pShip->vVel, &m_pShip->vPos );
  1184.          m_pShip->vVel.x *= -1.0f;
  1185.          m_pShip->vVel.y *= -1.0f;
  1186.          m_pShip->vVel.z *= -1.0f;
  1187.     }
  1188.  
  1189.     // Finally, move all objects on the screen
  1190.     for( pObject = m_pDisplayList; pObject; pObject = pObject->pNext )
  1191.     {
  1192.         // The ship is moved by the code above
  1193.         if( pObject->dwType == OBJ_SHIP )
  1194.             continue;
  1195.  
  1196.         C3DSprite* pSprite = (C3DSprite*)pObject;
  1197.  
  1198.         // Update the position and animation frame
  1199.         pSprite->vPos  += pSprite->vVel * fTimeLapsed;
  1200.         pSprite->frame += pSprite->delay * fTimeLapsed;
  1201.  
  1202.         // If this is an "expired" cloud, removed it from list
  1203.         if( pObject->dwType == OBJ_CLOUD )
  1204.         {
  1205.             if( pSprite->frame >= pSprite->fMaxFrame )
  1206.             {
  1207.                 DisplayObject* pVictim = pObject;
  1208.                 pObject = pObject->pPrev;
  1209.                 DeleteFromList( pVictim );
  1210.             }
  1211.         }
  1212.         else if( pObject->dwType == OBJ_BULLET )
  1213.         {
  1214.             // Remove bullets when they leave the scene
  1215.             if( pObject->vPos.x < -6.0f || pObject->vPos.x > +6.0f ||
  1216.                 pObject->vPos.y < -6.0f || pObject->vPos.y > +6.0f )
  1217.             {
  1218.                 DisplayObject* pVictim = pObject;
  1219.                 pObject = pObject->pPrev;
  1220.                 DeleteFromList( pVictim );
  1221.             }
  1222.         }
  1223.         else if( pObject->dwType != OBJ_CLOUD )
  1224.         {
  1225.             // Keep object in bounds in X
  1226.             if( pObject->vPos.x < -4.0f || pObject->vPos.x > +4.0f )
  1227.             {
  1228.                 if( pObject->vPos.x < -4.0f ) pObject->vPos.x = -4.0f;
  1229.                 if( pObject->vPos.x > +4.0f ) pObject->vPos.x = +4.0f;
  1230.                 pObject->vVel.x = -pObject->vVel.x;
  1231.             }
  1232.  
  1233.             // Keep object in bounds in Y
  1234.             if( pObject->vPos.y < -4.0f || pObject->vPos.y > +4.0f )
  1235.             {
  1236.                 if( pObject->vPos.y < -4.0f ) pObject->vPos.y = -4.0f;
  1237.                 if( pObject->vPos.y > +4.0f ) pObject->vPos.y = +4.0f;
  1238.                 pObject->vVel.y = -pObject->vVel.y;
  1239.             }
  1240.  
  1241.             // Keep animation frame in bounds
  1242.             if( pSprite->frame < 0.0f )
  1243.                 pSprite->frame += pSprite->fMaxFrame;
  1244.             if( pSprite->frame >= pSprite->fMaxFrame )
  1245.                 pSprite->frame -= pSprite->fMaxFrame;
  1246.         }
  1247.     }
  1248.  
  1249.     D3DXVECTOR3 vEyePt[NUMVIEWMODES];
  1250.     D3DXVECTOR3 vLookatPt[NUMVIEWMODES];
  1251.     D3DXVECTOR3 vUpVec[NUMVIEWMODES];
  1252.  
  1253.     // Update the view
  1254.     if( m_UserInput.bDoChangeView )
  1255.     {
  1256.         m_bAnimatingViewChange = TRUE;
  1257.         m_UserInput.bDoChangeView = FALSE;
  1258.     }
  1259.  
  1260.     if( m_bAnimatingViewChange )
  1261.     {
  1262.         m_fViewTransition += fTimeLapsed;
  1263.  
  1264.         if( m_fViewTransition >= 1.0f )
  1265.         {
  1266.             m_dwViewMode++;
  1267.             if( m_dwViewMode >= NUMVIEWMODES )
  1268.                 m_dwViewMode = 0;
  1269.  
  1270.             m_fViewTransition      = 0.0f;
  1271.             m_bAnimatingViewChange = FALSE;
  1272.         }
  1273.     }
  1274.  
  1275.     FLOAT fX =  m_pShip->vPos.x;
  1276.     FLOAT fZ = -m_pShip->vPos.y;
  1277.     FLOAT fY = 0.1f + HeightField( fX, fZ );
  1278.  
  1279.     // View mode 0 (third person)
  1280.     vEyePt[0]      = D3DXVECTOR3( fX-sinf(m_pShip->fAngle)/2, fY+0.2f, fZ-cosf(m_pShip->fAngle)/2 );
  1281.     vLookatPt[0]   = D3DXVECTOR3( fX+sinf(m_pShip->fAngle)/2, fY, fZ+cosf(m_pShip->fAngle)/2 );
  1282.     vUpVec[0]      = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  1283.  
  1284.     // View mode 1 (first person)
  1285.     FLOAT fX2 = fX+sinf(m_pShip->fAngle);
  1286.     FLOAT fZ2 = fZ+cosf(m_pShip->fAngle);
  1287.     FLOAT fY2 = 0.1f + HeightField( fX2, fZ2 );
  1288.     vEyePt[1]    = D3DXVECTOR3( fX, fY+0.1f, fZ );
  1289.     vLookatPt[1] = D3DXVECTOR3( fX2, fY2+0.1f, fZ2 );
  1290.     vUpVec[1]    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  1291.  
  1292.     // View mode 2 (top down view)
  1293.     vEyePt[2]    = D3DXVECTOR3( fX+1.5f, fY+1.5f, fZ+1.5f );
  1294.     vLookatPt[2] = D3DXVECTOR3( fX, fY, fZ );
  1295.     vUpVec[2]    = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
  1296.  
  1297.     DWORD start = m_dwViewMode;
  1298.     DWORD end   = ( start < (NUMVIEWMODES-1) ) ? m_dwViewMode+1: 0;
  1299.  
  1300.     if( start == 1 && m_fViewTransition<0.2f)
  1301.         m_bFirstPersonView = TRUE;
  1302.     else
  1303.         m_bFirstPersonView = FALSE;
  1304.  
  1305.     D3DXVECTOR3 vEyePt0    = (1.0f-m_fViewTransition)*vEyePt[start]    + m_fViewTransition*vEyePt[end];
  1306.     D3DXVECTOR3 vLookatPt0 = (1.0f-m_fViewTransition)*vLookatPt[start] + m_fViewTransition*vLookatPt[end];
  1307.     D3DXVECTOR3 vUpVec0    = (1.0f-m_fViewTransition)*vUpVec[start]    + m_fViewTransition*vUpVec[end];
  1308.  
  1309.     // Shake screen if ship exploded
  1310.     if( m_pShip->bExploded == TRUE )
  1311.         vEyePt0 += D3DXVECTOR3( rnd(), rnd(), rnd() ) * m_pShip->fShowDelay / 50.0f;
  1312.  
  1313.     m_Camera.SetViewParams( vEyePt0, vLookatPt0, vUpVec0 );
  1314. }
  1315.  
  1316.  
  1317.  
  1318.  
  1319. //-----------------------------------------------------------------------------
  1320. // Name: CheckForHits()
  1321. // Desc:
  1322. //-----------------------------------------------------------------------------
  1323. VOID CMyApplication::CheckForHits()
  1324. {
  1325.     DisplayObject* pObject;
  1326.     DisplayObject* pBullet;
  1327.  
  1328.     for( pBullet = m_pDisplayList; pBullet; pBullet = pBullet->pNext )
  1329.     {
  1330.         BOOL bBulletHit = FALSE;
  1331.  
  1332.         // Only bullet objects and the ship (if shieleds are on) can hit
  1333.         // other objects. Skip all others.
  1334.         if( (pBullet->dwType != OBJ_BULLET) && (pBullet->dwType != OBJ_SHIP) )
  1335.             continue;
  1336.  
  1337.         for( pObject = m_pDisplayList->pNext; pObject; pObject = pObject->pNext )
  1338.         {
  1339.             // Only trying to hit explodable targets
  1340.             if( ( pObject->dwType != OBJ_DONUT ) &&
  1341.                 ( pObject->dwType != OBJ_PYRAMID ) &&
  1342.                 ( pObject->dwType != OBJ_SPHERE ) &&
  1343.                 ( pObject->dwType != OBJ_CUBE ) )
  1344.                 continue;
  1345.  
  1346.             // Check if bullet is in radius of object
  1347.             FLOAT fDistance = D3DXVec3Length( &(pBullet->vPos - pObject->vPos) );
  1348.  
  1349.             if( fDistance < (pObject->fSize+pBullet->fSize) )
  1350.             {
  1351.                 // The object was hit
  1352.                 switch( pObject->dwType )
  1353.                 {
  1354.                     case OBJ_DONUT:
  1355.                         PlaySound( m_pDonutExplodeSound );
  1356.                         AddToList( new CPyramid( pObject->vPos, pObject->vVel ) );
  1357.                         AddToList( new CPyramid( pObject->vPos, pObject->vVel ) );
  1358.                         AddToList( new CPyramid( pObject->vPos, pObject->vVel ) );
  1359.                         AddToList( new CPyramid( pObject->vPos, pObject->vVel ) );
  1360.                         m_dwScore += 10;
  1361.                         break;
  1362.  
  1363.                     case OBJ_PYRAMID:
  1364.                         PlaySound( m_pPyramidExplodeSound );
  1365.                         AddToList( new CCube( pObject->vPos, pObject->vVel ) );
  1366.                         AddToList( new CCube( pObject->vPos, pObject->vVel ) );
  1367.                         AddToList( new CCube( pObject->vPos, pObject->vVel ) );
  1368.                         AddToList( new CCube( pObject->vPos, pObject->vVel ) );
  1369.                         m_dwScore += 20;
  1370.                         break;
  1371.  
  1372.                     case OBJ_CUBE:
  1373.                         PlaySound( m_pCubeExplodeSound );
  1374.                         AddToList( new CSphere( pObject->vPos, pObject->vVel ) );
  1375.                         m_dwScore += 40;
  1376.                         break;
  1377.  
  1378.                     case OBJ_SPHERE:
  1379.                         PlaySound( m_pSphereExplodeSound );
  1380.                         m_dwScore += 20;
  1381.                         break;
  1382.                 }
  1383.  
  1384.                 // Add explosion effects to scene
  1385.                 for( DWORD c=0; c<4; c++ )
  1386.                     AddToList( new CCloud( pObject->vPos, 0.05f*D3DXVECTOR3(rnd(),rnd(),0.0f) ) );
  1387.  
  1388.                 // Remove the victim from the scene
  1389.                 DisplayObject* pVictim = pObject;
  1390.                 pObject = pObject->pPrev;
  1391.                 DeleteFromList( pVictim );
  1392.  
  1393.                 bBulletHit = TRUE;
  1394.             }
  1395.  
  1396.             if( bBulletHit )
  1397.             {
  1398.                 if( pBullet->dwType == OBJ_SHIP )
  1399.                 {
  1400.                     bBulletHit = FALSE;
  1401.  
  1402.                     if( m_pShip->bVisible )
  1403.                     {
  1404.                         // Ship has exploded
  1405.                         PlaySound( m_pShipExplodeSound );
  1406.  
  1407.                         if( m_dwScore < 150 )
  1408.                             m_dwScore = 0;
  1409.                         else
  1410.                             m_dwScore -= 150;
  1411.  
  1412.                         // Add explosion debris to scene
  1413.                         for( DWORD sphere=0; sphere<4; sphere++ )
  1414.                             AddToList( new CSphere( m_pShip->vPos, pObject->vVel ) );
  1415.  
  1416.                         for( DWORD bullet=0; bullet<20; bullet++ )
  1417.                         {
  1418.                             FLOAT     angle     = D3DX_PI * rnd();
  1419.                             D3DVECTOR vDir      = D3DXVECTOR3(cosf(angle),sinf(angle),0.0f);
  1420.                             AddToList( new CBullet( m_pShip->vPos, 500.0f*vDir, 0 ) );
  1421.                         }
  1422.  
  1423.                         for( DWORD cloud=0; cloud<100; cloud++ )
  1424.                         {
  1425.                             FLOAT     magnitude = 1.0f + 0.1f*rnd();
  1426.                             FLOAT     angle     = D3DX_PI * rnd();
  1427.                             D3DVECTOR vDir      = D3DXVECTOR3(cosf(angle),sinf(angle),0.0f);
  1428.  
  1429.                             AddToList( new CCloud( m_pShip->vPos, magnitude*vDir ) );
  1430.                         }
  1431.  
  1432.                         // Clear out ship params
  1433.                         m_pShip->vVel.x = 0.0f;
  1434.                         m_pShip->vVel.y = 0.0f;
  1435.                         m_UserInput.fAxisMoveUD       = 0.0f;
  1436.                         m_UserInput.fAxisRotateLR         = 0.0f;
  1437.  
  1438.                         // Delay for 2 seconds before displaying ship
  1439.                         m_pShip->fShowDelay = 2.0f;
  1440.                         m_pShip->bVisible   = FALSE;
  1441.                         m_pShip->bExploded  = TRUE;
  1442.                     }
  1443.                 }
  1444.  
  1445.                 break;
  1446.             }
  1447.         }
  1448.  
  1449.         if( bBulletHit )
  1450.         {
  1451.             DisplayObject* pLastBullet = pBullet;
  1452.             pBullet = pBullet->pPrev;
  1453.             DeleteFromList( pLastBullet );
  1454.         }
  1455.     }
  1456. }
  1457.  
  1458.  
  1459.  
  1460.  
  1461. //-----------------------------------------------------------------------------
  1462. // Name: DrawDisplayList()
  1463. // Desc:
  1464. //-----------------------------------------------------------------------------
  1465. VOID CMyApplication::DrawDisplayList()
  1466. {
  1467.     TCHAR strBuffer[80];
  1468.  
  1469.     // Set the world matrix
  1470.     D3DXMATRIX matWorld;
  1471.     D3DXMatrixIdentity( &matWorld );
  1472.     m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  1473.  
  1474.     // Set the app view matrix for normal viewing
  1475.     m_pd3dDevice->SetTransform( D3DTS_VIEW, &m_Camera.GetViewMatrix() );
  1476.  
  1477.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  1478.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  1479.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  1480.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
  1481.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
  1482.     m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );
  1483.     m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );
  1484.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR );
  1485.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR );
  1486.     m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
  1487.     m_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, FALSE );
  1488.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  1489.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING,     TRUE );
  1490.     m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x33333333 );
  1491.  
  1492.     // Begin the scene
  1493.     if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
  1494.     {
  1495.         // Clear the display
  1496.         m_pd3dDevice->Clear( 0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 0L, 1.0f, 0L );
  1497.  
  1498.         // Draw the terrain
  1499.         m_pTerrain->Render( m_pd3dDevice );
  1500.  
  1501.         // Render the ship
  1502.         if( m_pShip->bVisible && m_bFirstPersonView == FALSE )
  1503.         {
  1504.             // Point of ship, on terrain
  1505.             D3DXVECTOR3 vShipPt;
  1506.             vShipPt.x =  m_pShip->vPos.x;
  1507.             vShipPt.z = -m_pShip->vPos.y;
  1508.             vShipPt.y = 0.1f + HeightField( vShipPt.x, vShipPt.z );
  1509.  
  1510.             // Point ahead of ship, on terrain
  1511.             D3DXVECTOR3 vForwardPt;
  1512.             vForwardPt.x = vShipPt.x+sinf(m_pShip->fAngle);
  1513.             vForwardPt.z = vShipPt.z+cosf(m_pShip->fAngle);
  1514.             vForwardPt.y = 0.1f + HeightField( vForwardPt.x, vForwardPt.z );
  1515.  
  1516.             // Point to side of ship, on terrain
  1517.             D3DXVECTOR3 vSidePt;
  1518.             vSidePt.x = vShipPt.x+sinf(m_pShip->fAngle + D3DX_PI/2.0f);
  1519.             vSidePt.z = vShipPt.z+cosf(m_pShip->fAngle + D3DX_PI/2.0f);
  1520.             vSidePt.y = 0.1f + HeightField( vSidePt.x, vSidePt.z );
  1521.  
  1522.             // Compute vectors of the ship's orientation
  1523.             D3DXVECTOR3 vForwardDir = vForwardPt - vShipPt;
  1524.             D3DXVECTOR3 vSideDir    = vSidePt - vShipPt;
  1525.             D3DXVECTOR3 vNormalDir;
  1526.             D3DXVec3Cross( &vNormalDir, &vForwardDir, &vSideDir );
  1527.  
  1528.             // Construct matrix to orient ship
  1529.             D3DXMATRIX matWorld, matLookAt, matRotateZ;
  1530.             D3DXMatrixRotationZ( &matRotateZ, m_pShip->fRoll );
  1531.             D3DXMatrixLookAtLH( &matLookAt, &vShipPt, &(vShipPt-vForwardDir), &vNormalDir );
  1532.             D3DXMatrixInverse( &matLookAt, NULL, &matLookAt );
  1533.             D3DXMatrixIdentity( &matWorld );
  1534.             D3DXMatrixMultiply( &matWorld, &matWorld, &matRotateZ );
  1535.             D3DXMatrixMultiply( &matWorld, &matWorld, &matLookAt );
  1536.  
  1537.             // Set renderstates for rendering the ship
  1538.             m_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
  1539.             m_pd3dDevice->SetRenderState( D3DRS_LIGHTING,           TRUE );
  1540.             m_pd3dDevice->SetRenderState( D3DRS_NORMALIZENORMALS,   TRUE );
  1541.             m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,   FALSE );
  1542.             m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,    FALSE );
  1543.  
  1544.             // Render the ship - opaque parts
  1545.             m_pShipFileObject->Render( m_pd3dDevice, TRUE, FALSE );
  1546.  
  1547.             // Render the ship - transparent parts
  1548.             m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE,   TRUE );
  1549.             m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  1550.             m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,     D3DBLEND_ONE );
  1551.             m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,    D3DBLEND_ONE );
  1552.             m_pShipFileObject->Render( m_pd3dDevice, FALSE, TRUE );
  1553.             m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
  1554.         }
  1555.  
  1556.         // Remaining objects don't need lighting
  1557.         m_pd3dDevice->SetRenderState( D3DRS_LIGHTING,           FALSE );
  1558.  
  1559.         // Enable alpha blending and testing
  1560.         m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
  1561.         m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );
  1562.         m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,         0x08 );
  1563.         m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL );
  1564.  
  1565.         // Display all visible objects in the display list
  1566.         for( DisplayObject* pObject = m_pDisplayList; pObject; pObject = pObject->pNext )
  1567.         {
  1568.             if( !pObject->bVisible )
  1569.                 continue;
  1570.             if( pObject->dwType == OBJ_SHIP )
  1571.                 continue;
  1572.             if( pObject->dwType == OBJ_BULLET )
  1573.                 continue;
  1574.  
  1575.             // This is really a 3D sprite
  1576.             C3DSprite* pSprite = (C3DSprite*)pObject;
  1577.  
  1578.             FLOAT fX =  pObject->vPos.x;
  1579.             FLOAT fZ = -pObject->vPos.y;
  1580.             FLOAT fY =  HeightField( fX, fZ );
  1581.  
  1582.             FLOAT x1 = -pObject->fSize;
  1583.             FLOAT x2 =  pObject->fSize;
  1584.             FLOAT y1 = -pObject->fSize;
  1585.             FLOAT y2 =  pObject->fSize;
  1586.  
  1587.             FLOAT u1 = (FLOAT)(pSprite->dwTextureOffsetX + pSprite->dwTextureWidth *(((int)pSprite->frame)%pSprite->dwFramesPerLine));
  1588.             FLOAT v1 = (FLOAT)(pSprite->dwTextureOffsetY + pSprite->dwTextureHeight*(((int)pSprite->frame)/pSprite->dwFramesPerLine));
  1589.  
  1590.             FLOAT tu1 = u1 / (256.0f-1.0f);
  1591.             FLOAT tv1 = v1 / (256.0f-1.0f);
  1592.             FLOAT tu2 = (u1 + pSprite->dwTextureWidth -1) / (256.0f-1.0f);
  1593.             FLOAT tv2 = (v1 + pSprite->dwTextureHeight-1) / (256.0f-1.0f);
  1594.  
  1595.             // Set the game texture
  1596.             switch( pObject->dwType )
  1597.             {
  1598.                 case OBJ_DONUT:
  1599.                 case OBJ_CUBE:
  1600.                 case OBJ_SPHERE:
  1601.                     m_pd3dDevice->SetTexture( 0, m_pGameTexture1 );
  1602.                     break;
  1603.                 case OBJ_PYRAMID:
  1604.                 case OBJ_CLOUD:
  1605.                     m_pd3dDevice->SetTexture( 0, m_pGameTexture2 );
  1606.                     break;
  1607.             }
  1608.  
  1609.             // Translate the billboard into place
  1610.             D3DXMATRIX mat = m_Camera.GetBillboardMatrix();
  1611.             mat._41 = fX;
  1612.             mat._42 = fY;
  1613.             mat._43 = fZ;
  1614.             m_pd3dDevice->SetTransform( D3DTS_WORLD, &mat );
  1615.  
  1616.             DWORD dwColor = pSprite->dwColor;
  1617.  
  1618.             m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA );
  1619.             m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
  1620.             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  1621.             m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
  1622.  
  1623.             if( pObject->dwType == OBJ_CLOUD )
  1624.             {
  1625.                 DWORD red = 255-(int)(pSprite->frame*255.0f);
  1626.                 DWORD grn = 255-(int)(pSprite->frame*511.0f);
  1627.                 DWORD blu = 255-(int)(pSprite->frame*1023.0f);
  1628.                 if( grn > 255 ) grn = 0;
  1629.                 if( blu > 255 ) blu = 0;
  1630.                 dwColor = 0xff000000 + (red<<16) + (grn<<8) + blu;
  1631.  
  1632.                 m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,  D3DBLEND_ONE );
  1633.                 m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
  1634.                 m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  1635.                 m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  1636.             }
  1637.  
  1638.             FLOAT h = 300.0f*pObject->vPos.z + 0.1f;
  1639.  
  1640.             SPRITEVERTEX* v;
  1641.             m_pSpriteVB->Lock( 0, 0, (BYTE**)&v, 0 );
  1642.             v[0].p = D3DXVECTOR3(x1,y1+h,0); v[0].color=dwColor; v[0].tu=tu1; v[0].tv=tv2;
  1643.             v[1].p = D3DXVECTOR3(x1,y2+h,0); v[1].color=dwColor; v[1].tu=tu1; v[1].tv=tv1;
  1644.             v[2].p = D3DXVECTOR3(x2,y1+h,0); v[2].color=dwColor; v[2].tu=tu2; v[2].tv=tv2;
  1645.             v[3].p = D3DXVECTOR3(x2,y2+h,0); v[3].color=dwColor; v[3].tu=tu2; v[3].tv=tv1;
  1646.             m_pSpriteVB->Unlock();
  1647.  
  1648.             // Render the billboarded sprite
  1649.             m_pd3dDevice->SetVertexShader( D3DFVF_SPRITEVERTEX );
  1650.             m_pd3dDevice->SetStreamSource( 0, m_pSpriteVB, sizeof(SPRITEVERTEX) );
  1651.             m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
  1652.         }
  1653.  
  1654.         // Display all bullets
  1655.         for( pObject = m_pDisplayList; pObject; pObject = pObject->pNext )
  1656.         {
  1657.             if( pObject->dwType != OBJ_BULLET )
  1658.                 continue;
  1659.  
  1660.             // This is really a 3D sprite
  1661.             C3DSprite* pSprite = (C3DSprite*)pObject;
  1662.  
  1663.             FLOAT u1 = (FLOAT)(pSprite->dwTextureOffsetX + pSprite->dwTextureWidth *(((int)pSprite->frame)%pSprite->dwFramesPerLine));
  1664.             FLOAT v1 = (FLOAT)(pSprite->dwTextureOffsetY + pSprite->dwTextureHeight*(((int)pSprite->frame)/pSprite->dwFramesPerLine));
  1665.             u1 = (FLOAT)(pSprite->dwTextureOffsetX);
  1666.             v1 = (FLOAT)(pSprite->dwTextureOffsetY);
  1667.  
  1668.             FLOAT tu1 = u1 / (256.0f-1.0f);
  1669.             FLOAT tv1 = v1 / (256.0f-1.0f);
  1670.             FLOAT tu2 = (u1 + pSprite->dwTextureWidth -1) / (256.0f-1.0f);
  1671.             FLOAT tv2 = (v1 + pSprite->dwTextureHeight-1) / (256.0f-1.0f);
  1672.  
  1673.             // Set render states
  1674.             m_pd3dDevice->SetTexture( 0, m_pGameTexture2 );
  1675.             m_pd3dDevice->SetVertexShader( D3DFVF_SPRITEVERTEX );
  1676.             m_pd3dDevice->SetStreamSource( 0, m_pSpriteVB, sizeof(SPRITEVERTEX) );
  1677.             m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,     D3DBLEND_ONE );
  1678.             m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,    D3DBLEND_ONE );
  1679.             m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  1680.             m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
  1681.  
  1682.             FLOAT x1 = -0.01f;
  1683.             FLOAT x2 =  0.01f;
  1684.             FLOAT y1 = -0.01f;
  1685.             FLOAT y2 =  0.01f;
  1686.  
  1687.             DWORD dwColor = pSprite->dwColor;
  1688.  
  1689.             for( DWORD a=0; a<6; a++ )
  1690.             {
  1691.                 FLOAT fX =  pObject->vPos.x - a*a*0.0005f*pObject->vVel.x;
  1692.                 FLOAT fZ = -pObject->vPos.y + a*a*0.0005f*pObject->vVel.y;
  1693.                 FLOAT fY =  HeightField( fX, fZ );
  1694.  
  1695.                 // Translate the billboard into place
  1696.                 D3DXMATRIX mat = m_Camera.GetBillboardMatrix();
  1697.                 mat._41 = fX;
  1698.                 mat._42 = fY;
  1699.                 mat._43 = fZ;
  1700.                 m_pd3dDevice->SetTransform( D3DTS_WORLD, &mat );
  1701.  
  1702.                 FLOAT h = 300.0f*pObject->vPos.z + 0.1f;
  1703.  
  1704.                 SPRITEVERTEX* v;
  1705.                 m_pSpriteVB->Lock( 0, 0, (BYTE**)&v, 0 );
  1706.                 v[0].p = D3DXVECTOR3(x1,y1+h,0); v[0].color=dwColor; v[0].tu=tu1; v[0].tv=tv2;
  1707.                 v[1].p = D3DXVECTOR3(x1,y2+h,0); v[1].color=dwColor; v[1].tu=tu1; v[1].tv=tv1;
  1708.                 v[2].p = D3DXVECTOR3(x2,y1+h,0); v[2].color=dwColor; v[2].tu=tu2; v[2].tv=tv2;
  1709.                 v[3].p = D3DXVECTOR3(x2,y2+h,0); v[3].color=dwColor; v[3].tu=tu2; v[3].tv=tv1;
  1710.                 m_pSpriteVB->Unlock();
  1711.  
  1712.                 // Render the billboarded sprite
  1713.                 m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
  1714.             }
  1715.         }
  1716.  
  1717.         // Restore state
  1718.         m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,      TRUE );
  1719.         m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
  1720.  
  1721.         // Display help
  1722.         _stprintf( strBuffer, _T("F1 for menu") );
  1723.         m_pGameFont->DrawTextScaled( -1.0f, 1.1f, 0.9f, 0.05f, 0.05f,
  1724.                                      0xffffff00, strBuffer, D3DFONT_FILTERED );
  1725.  
  1726.         // Display score
  1727.         _stprintf( strBuffer, _T("Score: %08ld"), m_dwScore );
  1728.         m_pGameFont->DrawTextScaled( -1.0f, 1.0f, 0.9f, 0.05f, 0.05f,
  1729.                                      0xffffff00, strBuffer, D3DFONT_FILTERED );
  1730.  
  1731.         // Display ship type
  1732.         _stprintf( strBuffer, _T("Ship: %s"), g_strShipNames[m_dwCurrentShipType] );
  1733.         m_pGameFont->DrawTextScaled( 0.0f, 1.0f, 0.9f, 0.05f, 0.05f,
  1734.                                      0xffffff00, strBuffer, D3DFONT_FILTERED );
  1735.  
  1736.         // Display weapon type
  1737.         TCHAR* strWeapon;
  1738.         if( m_dwBulletType == 0 )      strWeapon = _T("Weapon: Blaster");
  1739.         else if( m_dwBulletType == 1 ) strWeapon = _T("Weapon: Double blaster");
  1740.         else if( m_dwBulletType == 2 ) strWeapon = _T("Weapon: Spray gun");
  1741.         else                           strWeapon = _T("Weapon: Proximity killer");
  1742.         m_pGameFont->DrawTextScaled( 0.0f, 1.1f, 0.9f, 0.05f, 0.05f,
  1743.                                      0xffffff00, strWeapon, D3DFONT_FILTERED );
  1744.  
  1745.         // Render "Paused" text if game is paused
  1746.         if( m_bPaused && m_pGameFont )
  1747.         {
  1748.             DarkenScene( 0.5f );
  1749.             RenderFieryText( m_pMenuFont, _T("Paused") );
  1750.         }
  1751.  
  1752.         if( m_pShip->fShowDelay > 0.0f )
  1753.             DarkenScene( m_pShip->fShowDelay/2.0f );
  1754.  
  1755.         // Render game menu
  1756.         if( m_pCurrentMenu )
  1757.         {
  1758.             DarkenScene( 0.5f );
  1759.             m_pCurrentMenu->Render( m_pd3dDevice, m_pMenuFont );
  1760.         }
  1761.  
  1762.         m_pd3dDevice->EndScene();
  1763.     }
  1764. }
  1765.  
  1766.  
  1767.  
  1768.  
  1769. //-----------------------------------------------------------------------------
  1770. // Name: DeleteFromList()
  1771. // Desc:
  1772. //-----------------------------------------------------------------------------
  1773. VOID CMyApplication::DeleteFromList( DisplayObject* pObject )
  1774. {
  1775.     if( pObject->pNext )
  1776.         pObject->pNext->pPrev = pObject->pPrev;
  1777.     if( pObject->pPrev )
  1778.         pObject->pPrev->pNext = pObject->pNext;
  1779.     delete( pObject );
  1780. }
  1781.  
  1782.  
  1783.  
  1784.  
  1785. //-----------------------------------------------------------------------------
  1786. // Name:
  1787. // Desc:
  1788. //-----------------------------------------------------------------------------
  1789. VOID CMyApplication::ConstructMenus()
  1790. {
  1791.     // Build video sub menu
  1792.     CMenuItem* pVideoSubMenu = new CMenuItem( _T("Video Menu"), MENU_VIDEO );
  1793.     pVideoSubMenu->Add( new CMenuItem( _T("Windowed"), MENU_WINDOWED ) );
  1794.     pVideoSubMenu->Add( new CMenuItem( _T("640x480"),  MENU_640x480 ) );
  1795.     pVideoSubMenu->Add( new CMenuItem( _T("800x600"),  MENU_800x600 ) );
  1796.     pVideoSubMenu->Add( new CMenuItem( _T("1024x768"), MENU_1024x768 ) );
  1797.     pVideoSubMenu->Add( new CMenuItem( _T("Back"),     MENU_BACK ) );
  1798.  
  1799.     // Build sound menu
  1800.     CMenuItem* pSoundSubMenu = new CMenuItem( _T("Sound Menu"), MENU_SOUND );
  1801.     pSoundSubMenu->Add( new CMenuItem( _T("Sound On"),  MENU_SOUNDON ) );
  1802.     pSoundSubMenu->Add( new CMenuItem( _T("Sound Off"), MENU_SOUNDOFF ) );
  1803.     pSoundSubMenu->Add( new CMenuItem( _T("Back"),      MENU_BACK ) );
  1804.  
  1805.     // Build input menu
  1806.     CMenuItem* pInputSubMenu = new CMenuItem( _T("Input Menu"), MENU_INPUT );
  1807.     pInputSubMenu->Add( new CMenuItem( _T("View Devices"),   MENU_VIEWDEVICES ) );
  1808.     pInputSubMenu->Add( new CMenuItem( _T("Config Devices"), MENU_CONFIGDEVICES ) );
  1809.     pInputSubMenu->Add( new CMenuItem( _T("Back"),           MENU_BACK ) );
  1810.  
  1811.     // Build main menu
  1812.     m_pMainMenu = new CMenuItem( _T("Main Menu"),  MENU_MAIN );
  1813.     m_pMainMenu->Add( pVideoSubMenu );
  1814.     m_pMainMenu->Add( pSoundSubMenu );
  1815.     m_pMainMenu->Add( pInputSubMenu );
  1816.     m_pMainMenu->Add( new CMenuItem( _T("Back to Game"), MENU_BACK ) );
  1817.  
  1818.     // Build "quit game?" menu
  1819.     m_pQuitMenu = new CMenuItem( _T("Quit Game?"),  MENU_MAIN );
  1820.     m_pQuitMenu->Add( new CMenuItem( _T("Yes"),     MENU_QUIT ) );
  1821.     m_pQuitMenu->Add( new CMenuItem( _T("No"),      MENU_BACK ) );
  1822.  
  1823.     return;
  1824. }
  1825.  
  1826.  
  1827.  
  1828.  
  1829. //-----------------------------------------------------------------------------
  1830. // Name:
  1831. // Desc:
  1832. //-----------------------------------------------------------------------------
  1833. VOID CMyApplication::DestroyMenus()
  1834. {
  1835.     SAFE_DELETE( m_pQuitMenu );
  1836.     SAFE_DELETE( m_pMainMenu );
  1837. }
  1838.  
  1839.  
  1840.  
  1841.  
  1842. //-----------------------------------------------------------------------------
  1843. // Name: UpdateMenus()
  1844. // Desc:
  1845. //-----------------------------------------------------------------------------
  1846. VOID CMyApplication::UpdateMenus()
  1847. {
  1848.     if( m_pCurrentMenu == NULL )
  1849.         return;
  1850.  
  1851.     // Keep track of current selected menu, to check later for changes
  1852.     DWORD dwCurrentSelectedMenu = m_pCurrentMenu->dwSelectedMenu;
  1853.  
  1854.     // Check for menu up/down input
  1855.     if( m_UserInput.bDoMenuUp )
  1856.     {
  1857.         m_UserInput.bDoMenuUp = FALSE;
  1858.         if( m_pCurrentMenu->dwSelectedMenu > 0 )
  1859.             m_pCurrentMenu->dwSelectedMenu--;
  1860.     }
  1861.     else if( m_UserInput.bDoMenuDown )
  1862.     {
  1863.         m_UserInput.bDoMenuDown = FALSE;
  1864.         if( (m_pCurrentMenu->dwSelectedMenu+1) < m_pCurrentMenu->dwNumChildren )
  1865.             m_pCurrentMenu->dwSelectedMenu++;
  1866.     }
  1867.  
  1868.     // The the current menu changed, play a sound
  1869.     if( dwCurrentSelectedMenu != m_pCurrentMenu->dwSelectedMenu )
  1870.         PlaySound( m_pSphereExplodeSound );
  1871.  
  1872.     if( m_UserInput.bDoMenuSelect )
  1873.     {
  1874.         m_UserInput.bDoMenuSelect = FALSE;
  1875.         PlaySound( m_pSphereExplodeSound );
  1876.  
  1877.         DWORD dwID = m_pCurrentMenu->pChild[m_pCurrentMenu->dwSelectedMenu]->dwID;
  1878.  
  1879.         switch( dwID )
  1880.         {
  1881.             case MENU_BACK:
  1882.                 m_pCurrentMenu = m_pCurrentMenu->pParent;
  1883.                 break;
  1884.  
  1885.             case MENU_VIDEO:
  1886.             case MENU_SOUND:
  1887.             case MENU_INPUT:
  1888.                 m_pCurrentMenu = m_pCurrentMenu->pChild[m_pCurrentMenu->dwSelectedMenu];
  1889.                 break;
  1890.  
  1891.             case MENU_WINDOWED:
  1892.                 SwitchDisplayModes( FALSE, 0L, 0L );
  1893.                 m_pCurrentMenu = NULL;
  1894.                 break;
  1895.  
  1896.             case MENU_640x480:
  1897.                 SwitchDisplayModes( TRUE, 640, 480 );
  1898.                 m_pCurrentMenu = NULL;
  1899.                 break;
  1900.  
  1901.             case MENU_800x600:
  1902.                 SwitchDisplayModes( TRUE, 800, 600 );
  1903.                 m_pCurrentMenu = NULL;
  1904.                 break;
  1905.  
  1906.             case MENU_1024x768:
  1907.                 SwitchDisplayModes( TRUE, 1024, 768 );
  1908.                 m_pCurrentMenu = NULL;
  1909.                 break;
  1910.  
  1911.             case MENU_SOUNDON:
  1912.                 if( m_pMusicManager == NULL )
  1913.                     CreateSoundObjects( m_hWndMain );
  1914.                 m_pCurrentMenu = NULL;
  1915.                 break;
  1916.  
  1917.             case MENU_SOUNDOFF:
  1918.                 if( m_pMusicManager )
  1919.                     DestroySoundObjects();
  1920.                 m_pCurrentMenu = NULL;
  1921.                 break;
  1922.  
  1923.             case MENU_VIEWDEVICES:
  1924.             {
  1925.                 // Put action format to game play actions
  1926.                 m_pInputDeviceManager->SetActionFormat( m_diafGame, FALSE );
  1927.  
  1928.                 m_bMouseVisible = TRUE;
  1929.                 DXUtil_Timer( TIMER_STOP );
  1930.  
  1931.                 // Configure the devices (with view capability only)
  1932.                 if( m_bFullScreen )
  1933.                     m_pInputDeviceManager->ConfigureDevices( m_hWndMain,
  1934.                                                              m_pConfigSurface,
  1935.                                                              (VOID*)StaticConfigureInputDevicesCB,
  1936.                                                              DICD_DEFAULT, this );
  1937.                 else
  1938.                     m_pInputDeviceManager->ConfigureDevices( m_hWndMain, NULL, NULL,
  1939.                                                              DICD_DEFAULT, this );
  1940.  
  1941.                 m_bMouseVisible = FALSE;
  1942.                 DXUtil_Timer( TIMER_START );
  1943.  
  1944.                 m_pCurrentMenu = NULL;
  1945.                 break;
  1946.             }
  1947.  
  1948.             case MENU_CONFIGDEVICES:
  1949.             {
  1950.                 // Put action format to game play actions
  1951.                 m_pInputDeviceManager->SetActionFormat( m_diafGame, FALSE );
  1952.  
  1953.                 m_bMouseVisible = TRUE;
  1954.                 DXUtil_Timer( TIMER_STOP );
  1955.  
  1956.                 // Get access to the list of semantically-mapped input devices
  1957.                 // to delete all InputDeviceState structs before calling ConfigureDevices()
  1958.                 CInputDeviceManager::DeviceInfo* pDeviceInfos;
  1959.                 DWORD dwNumDevices;
  1960.                 m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  1961.  
  1962.                 for( DWORD i=0; i<dwNumDevices; i++ )
  1963.                 {
  1964.                     InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  1965.                     SAFE_DELETE( pInputDeviceState );
  1966.                     pDeviceInfos[i].pParam = NULL;
  1967.                 }
  1968.  
  1969.                 // Configure the devices (with edit capability)
  1970.                 if( m_bFullScreen )
  1971.                     m_pInputDeviceManager->ConfigureDevices( m_hWndMain,
  1972.                                                              m_pConfigSurface,
  1973.                                                              (VOID*)StaticConfigureInputDevicesCB,
  1974.                                                              DICD_EDIT, this );
  1975.                 else
  1976.                     m_pInputDeviceManager->ConfigureDevices( m_hWndMain, NULL, NULL,
  1977.                                                              DICD_EDIT, this );
  1978.  
  1979.                 DXUtil_Timer( TIMER_START );
  1980.                 m_bMouseVisible = FALSE;
  1981.  
  1982.                 m_pCurrentMenu = NULL;
  1983.                 break;
  1984.             }
  1985.  
  1986.             case MENU_QUIT:
  1987.                 PostMessage( m_hWndMain, WM_CLOSE, 0, 0 );
  1988.                 m_pCurrentMenu = NULL;
  1989.                 break;
  1990.         }
  1991.     }
  1992.  
  1993.     // Check if the menu system is being exitted
  1994.     if( m_UserInput.bDoMenuQuit )
  1995.     {
  1996.         m_UserInput.bDoMenuQuit = FALSE;
  1997.         m_pCurrentMenu = NULL;
  1998.     }
  1999.  
  2000.     // If the menu is going away, go back to game play actions
  2001.     if( m_pCurrentMenu == NULL )
  2002.         m_pInputDeviceManager->SetActionFormat( m_diafGame, FALSE );
  2003. }
  2004.  
  2005.  
  2006.  
  2007.  
  2008. //-----------------------------------------------------------------------------
  2009. // Display support code (using Direct3D functionality from D3DUtil.h)
  2010. //-----------------------------------------------------------------------------
  2011.  
  2012.  
  2013.  
  2014.  
  2015. //-----------------------------------------------------------------------------
  2016. // Name: CreateDisplayObjects()
  2017. // Desc:
  2018. //-----------------------------------------------------------------------------
  2019. HRESULT CMyApplication::CreateDisplayObjects( HWND hWnd )
  2020. {
  2021.     HRESULT hr, hr1, hr2;
  2022.  
  2023.     // Construct a new display
  2024.     LPDIRECT3D8 pD3D = Direct3DCreate8( D3D_SDK_VERSION );
  2025.     if( NULL == pD3D )
  2026.     {
  2027.         CleanupAndDisplayError( DONUTS3DERR_NODIRECT3D );
  2028.         return E_FAIL;
  2029.     }
  2030.  
  2031.     // Get the current desktop format
  2032.     pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &m_DesktopMode );
  2033.  
  2034.     const D3DFORMAT fmtFullscreenArray[] = 
  2035.     {
  2036.         D3DFMT_R5G6B5,
  2037.         D3DFMT_X1R5G5B5,
  2038.         D3DFMT_A1R5G5B5,
  2039.         D3DFMT_X8R8G8B8,
  2040.         D3DFMT_A8R8G8B8,
  2041.     };
  2042.     const INT numFullscreenFmts = sizeof(fmtFullscreenArray) / sizeof(fmtFullscreenArray[0]);
  2043.     INT iFmt;
  2044.  
  2045.     // Find a pixel format that will be good for fullscreen back buffers
  2046.     for( iFmt = 0; iFmt < numFullscreenFmts; iFmt++ )
  2047.     {
  2048.         if( SUCCEEDED( pD3D->CheckDeviceType( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
  2049.             fmtFullscreenArray[iFmt], fmtFullscreenArray[iFmt], FALSE ) ) )
  2050.         {
  2051.             m_d3dfmtFullscreen = fmtFullscreenArray[iFmt];
  2052.             break;
  2053.         }
  2054.     }
  2055.  
  2056.     const D3DFORMAT fmtTextureArray[] = 
  2057.     {
  2058.         D3DFMT_A1R5G5B5,
  2059.         D3DFMT_A4R4G4B4,
  2060.         D3DFMT_A8R8G8B8,
  2061.     };
  2062.     const INT numTextureFmts = sizeof(fmtTextureArray) / sizeof(fmtTextureArray[0]);
  2063.  
  2064.     // Find a format that is supported as a texture map for the current mode
  2065.     for( iFmt = 0; iFmt < numTextureFmts; iFmt++ )
  2066.     {
  2067.         if( SUCCEEDED( pD3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 
  2068.             m_DesktopMode.Format, 0, D3DRTYPE_TEXTURE, fmtTextureArray[iFmt] ) ) )
  2069.         {
  2070.             m_d3dfmtTexture = fmtTextureArray[iFmt];
  2071.             break;
  2072.         }
  2073.     }
  2074.  
  2075.     // Set up presentation parameters for the display
  2076.     ZeroMemory( &m_d3dpp, sizeof(m_d3dpp) );
  2077.     m_d3dpp.Windowed         = !m_bFullScreen;
  2078.     m_d3dpp.BackBufferCount  = 1;
  2079.     m_d3dpp.SwapEffect       = D3DSWAPEFFECT_DISCARD;
  2080.     m_d3dpp.EnableAutoDepthStencil = TRUE;
  2081.     m_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
  2082.     if( m_bFullScreen )
  2083.     {
  2084.         m_d3dpp.hDeviceWindow    = hWnd;
  2085.         m_d3dpp.BackBufferWidth  = m_dwScreenWidth;
  2086.         m_d3dpp.BackBufferHeight = m_dwScreenHeight;
  2087.         m_d3dpp.BackBufferFormat = m_d3dfmtFullscreen;
  2088.     }
  2089.     else
  2090.     {
  2091.         m_d3dpp.BackBufferFormat = m_DesktopMode.Format;
  2092.     }
  2093.  
  2094.     // Create the device
  2095.     hr = pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
  2096.                              D3DCREATE_SOFTWARE_VERTEXPROCESSING,
  2097.                              &m_d3dpp, &m_pd3dDevice );
  2098.     pD3D->Release();
  2099.     if( FAILED(hr) )
  2100.     {
  2101.         CleanupAndDisplayError( DONUTS3DERR_NOD3DDEVICE );
  2102.         return E_FAIL;
  2103.     }
  2104.  
  2105.     // Create some game fonts
  2106.     m_pGameFont = new CD3DFont( _T("Tahoma"), 30, 0L );
  2107.     m_pGameFont->InitDeviceObjects( m_pd3dDevice );
  2108.  
  2109.     m_pMenuFont = new CD3DFont( _T("Impact"), 48, 0L );
  2110.     m_pMenuFont->InitDeviceObjects( m_pd3dDevice );
  2111.  
  2112.     // Find the media files (textures and geometry models) for the game
  2113.     TCHAR strGameTexture1[512];
  2114.     TCHAR strGameTexture2[512];
  2115.     hr1 = DXUtil_FindMediaFile( strGameTexture1, _T("Donuts1.bmp") );
  2116.     hr2 = DXUtil_FindMediaFile( strGameTexture2, _T("Donuts2.bmp") );
  2117.  
  2118.     if( FAILED(hr1) || FAILED(hr2) )
  2119.     {
  2120.         CleanupAndDisplayError( DONUTS3DERR_NOTEXTURES );
  2121.         return E_FAIL;
  2122.     }
  2123.  
  2124.     // Load the game textures
  2125.     if( FAILED( D3DUtil_CreateTexture( m_pd3dDevice, strGameTexture1,
  2126.                                        &m_pGameTexture1, m_d3dfmtTexture ) ) ||
  2127.         FAILED( D3DUtil_CreateTexture( m_pd3dDevice, strGameTexture2,
  2128.                                        &m_pGameTexture2, m_d3dfmtTexture ) ) )
  2129.     {
  2130.         CleanupAndDisplayError( DONUTS3DERR_NOTEXTURES );
  2131.         return E_FAIL;
  2132.     }
  2133.  
  2134.     D3DUtil_SetColorKey( m_pGameTexture1, 0x00000000 );
  2135.     D3DUtil_SetColorKey( m_pGameTexture2, 0x00000000 );
  2136.  
  2137.     // Load the geometry models
  2138.     hr1 = LoadShipModel();
  2139.     hr2 = LoadTerrainModel();
  2140.  
  2141.     if( FAILED(hr1) || FAILED(hr2) )
  2142.     {
  2143.         CleanupAndDisplayError( DONUTS3DERR_NOGEOMETRY );
  2144.         return E_FAIL;
  2145.     }
  2146.  
  2147.     // Create a viewport covering sqaure
  2148.     if( FAILED( m_pd3dDevice->CreateVertexBuffer( 4*sizeof(SCREENVERTEX),
  2149.                                        D3DUSAGE_WRITEONLY, D3DFVF_SCREENVERTEX,
  2150.                                        D3DPOOL_MANAGED, &m_pViewportVB ) ) )
  2151.     {
  2152.         CleanupAndDisplayError( DONUTS3DERR_NO3DRESOURCES );
  2153.         return E_FAIL;
  2154.     }
  2155.  
  2156.     // Create a sqaure for rendering the sprites
  2157.     if( FAILED( m_pd3dDevice->CreateVertexBuffer( 4*sizeof(SPRITEVERTEX),
  2158.                                        D3DUSAGE_WRITEONLY, D3DFVF_SPRITEVERTEX,
  2159.                                        D3DPOOL_MANAGED, &m_pSpriteVB ) ) )
  2160.     {
  2161.         CleanupAndDisplayError( DONUTS3DERR_NO3DRESOURCES );
  2162.         return E_FAIL;
  2163.     }
  2164.  
  2165.     // Now that all the display objects are created, "restore" them (create
  2166.     // local mem objects and set state)
  2167.     if( FAILED( RestoreDisplayObjects() ) )
  2168.                 return E_FAIL;
  2169.  
  2170.         // The display is now ready
  2171.         m_bDisplayReady = TRUE;
  2172.         return S_OK;
  2173. }
  2174.  
  2175.  
  2176.  
  2177.  
  2178. //-----------------------------------------------------------------------------
  2179. // Name: RestoreDisplayObjects()
  2180. // Desc:
  2181. //-----------------------------------------------------------------------------
  2182. HRESULT CMyApplication::RestoreDisplayObjects()
  2183. {
  2184.     HRESULT hr;
  2185.     HWND hWnd = m_hWndMain;
  2186.  
  2187.     if( FALSE == m_bFullScreen )
  2188.     {
  2189.         // If we are still a WS_POPUP window we should convert to a normal app
  2190.         // window so we look like a windows app.
  2191.         DWORD dwStyle  = GetWindowStyle( hWnd );
  2192.         dwStyle &= ~WS_POPUP;
  2193.         dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX;
  2194.         SetWindowLong( hWnd, GWL_STYLE, dwStyle );
  2195.  
  2196.         // Aet window size
  2197.         RECT rc;
  2198.         SetRect( &rc, 0, 0, 640, 480 );
  2199.  
  2200.         AdjustWindowRectEx( &rc, GetWindowStyle(hWnd), GetMenu(hWnd) != NULL,
  2201.                             GetWindowExStyle(hWnd) );
  2202.  
  2203.         SetWindowPos( hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
  2204.                       SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
  2205.  
  2206.         SetWindowPos( hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
  2207.                       SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
  2208.  
  2209.         //  Make sure our window does not hang outside of the work area
  2210.         RECT rcWork;
  2211.         SystemParametersInfo( SPI_GETWORKAREA, 0, &rcWork, 0 );
  2212.         GetWindowRect( hWnd, &rc );
  2213.         if( rc.left < rcWork.left ) rc.left = rcWork.left;
  2214.         if( rc.top  < rcWork.top )  rc.top  = rcWork.top;
  2215.         SetWindowPos( hWnd, NULL, rc.left, rc.top, 0, 0,
  2216.                       SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
  2217.     }
  2218.  
  2219.     // Create the device-dependent objects for the file-based mesh objects
  2220.     m_pShipFileObject->RestoreDeviceObjects( m_pd3dDevice );
  2221.     m_pTerrain->RestoreDeviceObjects( m_pd3dDevice );
  2222.     m_pGameFont->RestoreDeviceObjects();
  2223.     m_pMenuFont->RestoreDeviceObjects();
  2224.  
  2225.     // Get viewport dimensions
  2226.     D3DVIEWPORT8 vp;
  2227.     m_pd3dDevice->GetViewport(&vp);
  2228.     FLOAT sx = (FLOAT)vp.Width;
  2229.     FLOAT sy = (FLOAT)vp.Height;
  2230.  
  2231.     // Setup dimensions for the viewport covering sqaure
  2232.     SCREENVERTEX* v;
  2233.     m_pViewportVB->Lock( 0, 0, (BYTE**)&v, 0 );
  2234.     v[0].p = D3DXVECTOR4( 0,sy,0.0f,1.0f);
  2235.     v[1].p = D3DXVECTOR4( 0, 0,0.0f,1.0f);
  2236.     v[2].p = D3DXVECTOR4(sx,sy,0.0f,1.0f);
  2237.     v[3].p = D3DXVECTOR4(sx, 0,0.0f,1.0f);
  2238.     m_pViewportVB->Unlock();
  2239.  
  2240.     // Create a surface for confguring DInput devices
  2241.     hr = m_pd3dDevice->CreateImageSurface( 640, 480, m_d3dfmtFullscreen, &m_pConfigSurface );
  2242.     if( FAILED(hr) )
  2243.     {
  2244.         CleanupAndDisplayError( DONUTS3DERR_NO3DRESOURCES );
  2245.         return E_FAIL;
  2246.     }
  2247.  
  2248.     // Set up the camera
  2249.     m_Camera.SetViewParams( D3DXVECTOR3(0.0f,0.0f,0.0f), D3DXVECTOR3(0.0f,0.0f,1.0f),
  2250.                             D3DXVECTOR3(0.0f,1.0f,0.0f) );
  2251.     m_Camera.SetProjParams( D3DX_PI/4, 1.0f, 0.1f, 100.0f );
  2252.  
  2253.     // Set up default matrices (using the CD3DCamera class)
  2254.     m_pd3dDevice->SetTransform( D3DTS_VIEW,       &m_Camera.GetViewMatrix() );
  2255.     m_pd3dDevice->SetTransform( D3DTS_PROJECTION, &m_Camera.GetProjMatrix() );
  2256.  
  2257.     // Setup a material
  2258.     D3DMATERIAL8 mtrl;
  2259.     D3DUtil_InitMaterial( mtrl, 1.0f, 1.0f, 1.0f );
  2260.     m_pd3dDevice->SetMaterial( &mtrl );
  2261.  
  2262.     // Set up lighting states
  2263.     D3DLIGHT8 light;
  2264.     D3DUtil_InitLight( light, D3DLIGHT_DIRECTIONAL, 1.0f, -1.0f, 1.0f );
  2265.     m_pd3dDevice->SetLight( 0, &light );
  2266.     m_pd3dDevice->LightEnable( 0, TRUE );
  2267.  
  2268.     m_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE );
  2269.     m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0x33333333 );
  2270.  
  2271.     // Set miscellaneous render states
  2272.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
  2273.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
  2274.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
  2275.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_POINT );
  2276.     m_pd3dDevice->SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_POINT );
  2277.     m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
  2278.  
  2279.     return S_OK;
  2280. }
  2281.  
  2282.  
  2283.  
  2284.  
  2285. //-----------------------------------------------------------------------------
  2286. // Name: InvalidateDisplayObjects()
  2287. // Desc:
  2288. //-----------------------------------------------------------------------------
  2289. HRESULT CMyApplication::InvalidateDisplayObjects()
  2290. {
  2291.     m_pShipFileObject->InvalidateDeviceObjects();
  2292.     m_pTerrain->InvalidateDeviceObjects();
  2293.     m_pGameFont->InvalidateDeviceObjects();
  2294.     m_pMenuFont->InvalidateDeviceObjects();
  2295.  
  2296.     SAFE_RELEASE( m_pConfigSurface );
  2297.  
  2298.     return S_OK;
  2299. }
  2300.  
  2301.  
  2302.  
  2303. //-----------------------------------------------------------------------------
  2304. // Name: DestroyDisplayObjects()
  2305. // Desc:
  2306. //-----------------------------------------------------------------------------
  2307. HRESULT CMyApplication::DestroyDisplayObjects()
  2308. {
  2309.     DisplayObject* pDO;
  2310.     while( m_pDisplayList != NULL )
  2311.     {
  2312.         pDO = m_pDisplayList;
  2313.         m_pDisplayList = m_pDisplayList->pNext;
  2314.         delete pDO;
  2315.         if( m_pDisplayList != NULL)
  2316.             m_pDisplayList->pPrev = NULL;
  2317.     }
  2318.     
  2319.     SAFE_RELEASE( m_pGameTexture1 );
  2320.     SAFE_RELEASE( m_pGameTexture2 );
  2321.  
  2322.     SAFE_DELETE( m_pGameFont );
  2323.     SAFE_DELETE( m_pMenuFont );
  2324.  
  2325.     SAFE_RELEASE( m_pConfigSurface );
  2326.  
  2327.     if( m_pShipFileObject != NULL )
  2328.         m_pShipFileObject->Destroy();
  2329.     if( m_pTerrain != NULL )
  2330.         m_pTerrain->Destroy();
  2331.  
  2332.     SAFE_DELETE( m_pTerrain );
  2333.     SAFE_DELETE( m_pShipFileObject );
  2334.  
  2335.     SAFE_RELEASE( m_pViewportVB );
  2336.     SAFE_RELEASE( m_pSpriteVB );
  2337.     SAFE_RELEASE( m_pd3dDevice );
  2338.  
  2339.     return S_OK;
  2340. }
  2341.  
  2342.  
  2343.  
  2344.  
  2345. //-----------------------------------------------------------------------------
  2346. // Name: SwitchDisplayModes()
  2347. // Desc:
  2348. //-----------------------------------------------------------------------------
  2349. HRESULT CMyApplication::SwitchDisplayModes( BOOL bFullScreen, DWORD dwWidth, DWORD dwHeight )
  2350. {
  2351.     HRESULT hr;
  2352.  
  2353.     if( FALSE==m_bIsActive || FALSE==m_bDisplayReady )
  2354.         return S_OK;
  2355.  
  2356.     // Check to see if a change was actually requested
  2357.     if( bFullScreen )
  2358.     {
  2359.         if( m_dwScreenWidth==dwWidth && m_dwScreenHeight==dwHeight &&
  2360.             m_bFullScreen==bFullScreen )
  2361.             return S_OK;
  2362.     }
  2363.     else
  2364.     {
  2365.         if( m_bFullScreen == FALSE )
  2366.             return S_OK;
  2367.     }
  2368.  
  2369.     // Invalidate the old display objects
  2370.     m_bDisplayReady = FALSE;
  2371.     InvalidateDisplayObjects();
  2372.  
  2373.     // Set up the new presentation paramters
  2374.     if( bFullScreen )
  2375.     {
  2376.         m_d3dpp.Windowed         = FALSE;
  2377.         m_d3dpp.hDeviceWindow    = m_hWndMain;
  2378.         m_d3dpp.BackBufferWidth  = m_dwScreenWidth  = dwWidth;
  2379.         m_d3dpp.BackBufferHeight = m_dwScreenHeight = dwHeight;
  2380.         m_d3dpp.BackBufferFormat = m_d3dfmtFullscreen;
  2381.     }
  2382.     else
  2383.     {
  2384.         m_d3dpp.Windowed         = TRUE;
  2385.         m_d3dpp.hDeviceWindow    = NULL;
  2386.         m_d3dpp.BackBufferWidth  = 0L;
  2387.         m_d3dpp.BackBufferHeight = 0L;
  2388.  
  2389.         m_d3dpp.BackBufferFormat = m_DesktopMode.Format;
  2390.     }
  2391.  
  2392.     // Reset the device
  2393.     if( SUCCEEDED( hr = m_pd3dDevice->Reset( &m_d3dpp ) ) )
  2394.     {
  2395.         m_bFullScreen   = bFullScreen;
  2396.         if( SUCCEEDED( hr = RestoreDisplayObjects() ) )
  2397.         {
  2398.             m_bDisplayReady = TRUE;
  2399.             SetCursor( NULL );
  2400.             return S_OK;
  2401.         }
  2402.     }
  2403.  
  2404.     // If we get here, a fatal error occurred
  2405.     PostMessage( m_hWndMain, WM_CLOSE, 0, 0 );
  2406.     return E_FAIL;
  2407. }
  2408.  
  2409.  
  2410.  
  2411.  
  2412. //-----------------------------------------------------------------------------
  2413. // Name: ShowFrame()
  2414. // Desc:
  2415. //-----------------------------------------------------------------------------
  2416. VOID CMyApplication::ShowFrame()
  2417. {
  2418.     if( NULL == m_pd3dDevice )
  2419.         return;
  2420.  
  2421.     // Present the backbuffer contents to the front buffer
  2422.     m_pd3dDevice->Present( 0, 0, 0, 0 );
  2423. }
  2424.  
  2425.  
  2426.  
  2427.  
  2428. //-----------------------------------------------------------------------------
  2429. // Sound support code (using DMusic functionality from DMUtil.h)
  2430. //-----------------------------------------------------------------------------
  2431.  
  2432.  
  2433.  
  2434.  
  2435. //-----------------------------------------------------------------------------
  2436. // Name: CreateSoundObjects()
  2437. // Desc:
  2438. //-----------------------------------------------------------------------------
  2439. HRESULT CMyApplication::CreateSoundObjects( HWND hWnd )
  2440. {
  2441.     // Create the music manager class, used to create the sounds
  2442.     m_pMusicManager = new CMusicManager();
  2443.     if( FAILED( m_pMusicManager->Initialize( hWnd ) ) )
  2444.         return E_FAIL;
  2445.  
  2446.     // Instruct the music manager where to find the files
  2447.     m_pMusicManager->SetSearchDirectory( DXUtil_GetDXSDKMediaPath() );
  2448.  
  2449.     // Create the sounds
  2450.     m_pMusicManager->CreateSegmentFromResource( &m_pBeginLevelSound,     _T("BEGINLEVEL"), _T("WAV") );
  2451.     m_pMusicManager->CreateSegmentFromResource( &m_pEngineIdleSound,     _T("ENGINEIDLE") , _T("WAV"));
  2452.     m_pMusicManager->CreateSegmentFromResource( &m_pEngineRevSound,      _T("ENGINEREV") , _T("WAV"));
  2453.     m_pMusicManager->CreateSegmentFromResource( &m_pShieldBuzzSound,     _T("SHIELDBUZZ") , _T("WAV"));
  2454.     m_pMusicManager->CreateSegmentFromResource( &m_pShipExplodeSound,    _T("SHIPEXPLODE") , _T("WAV"));
  2455.     m_pMusicManager->CreateSegmentFromResource( &m_pFireBulletSound,     _T("GUNFIRE") , _T("WAV"));
  2456.     m_pMusicManager->CreateSegmentFromResource( &m_pShipBounceSound,     _T("SHIPBOUNCE") , _T("WAV"));
  2457.     m_pMusicManager->CreateSegmentFromResource( &m_pDonutExplodeSound,   _T("DONUTEXPLODE") , _T("WAV"));
  2458.     m_pMusicManager->CreateSegmentFromResource( &m_pPyramidExplodeSound, _T("PYRAMIDEXPLODE") , _T("WAV"));
  2459.     m_pMusicManager->CreateSegmentFromResource( &m_pCubeExplodeSound,    _T("CUBEEXPLODE") , _T("WAV"));
  2460.     m_pMusicManager->CreateSegmentFromResource( &m_pSphereExplodeSound,  _T("SPHEREEXPLODE") , _T("WAV"));
  2461.  
  2462.     return S_OK;
  2463. }
  2464.  
  2465.  
  2466.  
  2467.  
  2468. //-----------------------------------------------------------------------------
  2469. // Name: DestroySoundObjects()
  2470. // Desc:
  2471. //-----------------------------------------------------------------------------
  2472. VOID CMyApplication::DestroySoundObjects()
  2473. {
  2474.     SAFE_DELETE( m_pBeginLevelSound );
  2475.     SAFE_DELETE( m_pEngineIdleSound );
  2476.     SAFE_DELETE( m_pEngineRevSound );
  2477.     SAFE_DELETE( m_pShieldBuzzSound );
  2478.     SAFE_DELETE( m_pShipExplodeSound );
  2479.     SAFE_DELETE( m_pFireBulletSound );
  2480.     SAFE_DELETE( m_pShipBounceSound );
  2481.     SAFE_DELETE( m_pDonutExplodeSound );
  2482.     SAFE_DELETE( m_pPyramidExplodeSound );
  2483.     SAFE_DELETE( m_pCubeExplodeSound );
  2484.     SAFE_DELETE( m_pSphereExplodeSound );
  2485.  
  2486.     SAFE_DELETE( m_pMusicManager );
  2487. }
  2488.  
  2489.  
  2490.  
  2491.  
  2492. //-----------------------------------------------------------------------------
  2493. // Input support code (using DInput functionality from DIUtil.h)
  2494. //-----------------------------------------------------------------------------
  2495.  
  2496.  
  2497.  
  2498. //-----------------------------------------------------------------------------
  2499. // Name: CreateInputObjects()
  2500. // Desc:
  2501. //-----------------------------------------------------------------------------
  2502. HRESULT CMyApplication::CreateInputObjects( HWND hWnd )
  2503. {
  2504.     HRESULT hr;
  2505.  
  2506.     // Setup action format for the acutal gameplay
  2507.     ZeroMemory( &m_diafGame, sizeof(DIACTIONFORMAT) );
  2508.     m_diafGame.dwSize          = sizeof(DIACTIONFORMAT);
  2509.     m_diafGame.dwActionSize    = sizeof(DIACTION);
  2510.     m_diafGame.dwDataSize      = NUMBER_OF_GAMEACTIONS * sizeof(DWORD);
  2511.     m_diafGame.guidActionMap   = g_guidApp;
  2512.     m_diafGame.dwGenre         = DIVIRTUAL_SPACESIM;
  2513.     m_diafGame.dwNumActions    = NUMBER_OF_GAMEACTIONS;
  2514.     m_diafGame.rgoAction       = g_rgGameAction;
  2515.     m_diafGame.lAxisMin        = -10;
  2516.     m_diafGame.lAxisMax        = 10;
  2517.     m_diafGame.dwBufferSize    = 16;
  2518.     _tcscpy( m_diafGame.tszActionMap, _T("Donuts3D New") );
  2519.  
  2520.     // Setup action format for the in-game menus
  2521.     ZeroMemory( &m_diafBrowser, sizeof(DIACTIONFORMAT) );
  2522.     m_diafBrowser.dwSize          = sizeof(DIACTIONFORMAT);
  2523.     m_diafBrowser.dwActionSize    = sizeof(DIACTION);
  2524.     m_diafBrowser.dwDataSize      = NUMBER_OF_BROWSERACTIONS * sizeof(DWORD);
  2525.     m_diafBrowser.guidActionMap   = g_guidApp;
  2526.     m_diafBrowser.dwGenre         = DIVIRTUAL_BROWSER_CONTROL;
  2527.     m_diafBrowser.dwNumActions    = NUMBER_OF_BROWSERACTIONS;
  2528.     m_diafBrowser.rgoAction       = g_rgBrowserAction;
  2529.     m_diafBrowser.lAxisMin        = -10;
  2530.     m_diafBrowser.lAxisMax        = 10;
  2531.     m_diafBrowser.dwBufferSize    = 16;
  2532.     _tcscpy( m_diafBrowser.tszActionMap, _T("Donuts New") );
  2533.  
  2534.     // Create a new input device manager
  2535.     m_pInputDeviceManager = new CInputDeviceManager();
  2536.  
  2537.     if( FAILED( hr = m_pInputDeviceManager->Create( hWnd, NULL, m_diafGame,
  2538.                                                     StaticInputAddDeviceCB, this ) ) )
  2539.     {
  2540.         CleanupAndDisplayError( DONUTS3DERR_NOINPUT );
  2541.         return E_FAIL;
  2542.     }
  2543.  
  2544.     return S_OK;
  2545. }
  2546.  
  2547.  
  2548.  
  2549.  
  2550. //-----------------------------------------------------------------------------
  2551. // Name: StaticInputAddDeviceCB()
  2552. // Desc: Static callback helper to call into CMyApplication class
  2553. //-----------------------------------------------------------------------------
  2554. HRESULT CALLBACK CMyApplication::StaticInputAddDeviceCB( 
  2555.                                          CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  2556.                                          const DIDEVICEINSTANCE* pdidi, 
  2557.                                          LPVOID pParam )
  2558. {
  2559.     CMyApplication* pApp = (CMyApplication*) pParam;
  2560.     return pApp->InputAddDeviceCB( pDeviceInfo, pdidi );
  2561. }
  2562.  
  2563.  
  2564.  
  2565.  
  2566. //-----------------------------------------------------------------------------
  2567. // Name: InputAddDeviceCB()
  2568. // Desc: Called from CInputDeviceManager whenever a device is added. 
  2569. //       Set the dead zone, and creates a new InputDeviceState for each device
  2570. //-----------------------------------------------------------------------------
  2571. HRESULT CMyApplication::InputAddDeviceCB( CInputDeviceManager::DeviceInfo* pDeviceInfo, 
  2572.                                                    const DIDEVICEINSTANCE* pdidi )
  2573. {
  2574.     // Setup the deadzone 
  2575.     DIPROPDWORD dipdw;
  2576.     dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
  2577.     dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  2578.     dipdw.diph.dwObj        = 0;
  2579.     dipdw.diph.dwHow        = DIPH_DEVICE;
  2580.     dipdw.dwData            = 500;
  2581.     pDeviceInfo->pdidDevice->SetProperty( DIPROP_DEADZONE, &dipdw.diph );
  2582.     
  2583.     if( GET_DIDEVICE_TYPE(pdidi->dwDevType) == DI8DEVTYPE_MOUSE )
  2584.         pDeviceInfo->pdidDevice->SetCooperativeLevel( m_hWndMain, DISCL_EXCLUSIVE|DISCL_FOREGROUND );
  2585.  
  2586.     // Create a new InputDeviceState for each device so the 
  2587.     // app can record its state 
  2588.     InputDeviceState* pNewInputDeviceState = new InputDeviceState;
  2589.     ZeroMemory( pNewInputDeviceState, sizeof(InputDeviceState) );
  2590.     pDeviceInfo->pParam = (LPVOID) pNewInputDeviceState;
  2591.  
  2592.     return S_OK;
  2593. }
  2594.  
  2595.  
  2596.  
  2597.  
  2598. //-----------------------------------------------------------------------------
  2599. // Name: DestroyInputObjects()
  2600. // Desc:
  2601. //-----------------------------------------------------------------------------
  2602. VOID CMyApplication::DestroyInputObjects()
  2603. {
  2604.     if( m_pInputDeviceManager )
  2605.     {
  2606.         // Get access to the list of semantically-mapped input devices
  2607.         // to delete all InputDeviceState structs
  2608.         CInputDeviceManager::DeviceInfo* pDeviceInfos;
  2609.         DWORD dwNumDevices;
  2610.         m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  2611.     
  2612.         for( DWORD i=0; i<dwNumDevices; i++ )
  2613.         {
  2614.             InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  2615.             SAFE_DELETE( pInputDeviceState );
  2616.             pDeviceInfos[i].pParam = NULL;
  2617.         }
  2618.     
  2619.         // Delete input device manager
  2620.         SAFE_DELETE( m_pInputDeviceManager );
  2621.     }
  2622. }
  2623.  
  2624.  
  2625.  
  2626.  
  2627.  
  2628. //-----------------------------------------------------------------------------
  2629. // Name: StaticConfigureInputDevicesCB()
  2630. // Desc: Static callback helper to call into CMyD3DApplication class
  2631. //-----------------------------------------------------------------------------
  2632. BOOL CALLBACK CMyApplication::StaticConfigureInputDevicesCB( IUnknown* pUnknown, VOID* pUserData )
  2633. {
  2634.     CMyApplication* pApp = (CMyApplication*) pUserData;
  2635.     return pApp->ConfigureInputDevicesCB( pUnknown );
  2636. }
  2637.  
  2638.  
  2639.  
  2640. //-----------------------------------------------------------------------------
  2641. // Name: ConfigureInputDevicesCB()
  2642. // Desc: Callback function for configuring input devices. This function is
  2643. //       called in fullscreen modes, so that the input device configuration
  2644. //       window can update the screen.
  2645. //-----------------------------------------------------------------------------
  2646. BOOL CMyApplication::ConfigureInputDevicesCB( IUnknown* pUnknown )
  2647. {
  2648.     if( m_dwAppState != APPSTATE_ACTIVE )
  2649.         return TRUE;
  2650.  
  2651.     // Get access to the surface
  2652.     LPDIRECT3DSURFACE8 pConfigSurface;
  2653.     if( FAILED( pUnknown->QueryInterface( IID_IDirect3DSurface8,
  2654.                                           (VOID**)&pConfigSurface ) ) )
  2655.         return TRUE;
  2656.  
  2657.     // Draw the scene, with the config surface blitted on top
  2658.     DrawDisplayList();
  2659.  
  2660.     RECT  rcSrc;
  2661.     SetRect( &rcSrc, 0, 0, 640, 480 );
  2662.  
  2663.     POINT ptDst;
  2664.     ptDst.x = (m_dwScreenWidth-640)/2;
  2665.     ptDst.y = (m_dwScreenHeight-480)/2;
  2666.  
  2667.     LPDIRECT3DSURFACE8 pBackBuffer;
  2668.     m_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer );
  2669.     m_pd3dDevice->CopyRects( pConfigSurface, &rcSrc, 1, pBackBuffer, &ptDst );
  2670.     pBackBuffer->Release();
  2671.  
  2672.     ShowFrame();
  2673.  
  2674.     // Release the surface
  2675.     pConfigSurface->Release();
  2676.  
  2677.     return TRUE;
  2678. }
  2679.  
  2680.  
  2681.  
  2682.  
  2683. //-----------------------------------------------------------------------------
  2684. // Name: GetInput()
  2685. // Desc: Processes data from the input device.  Uses GetDeviceState().
  2686. //-----------------------------------------------------------------------------
  2687. void CMyApplication::UpdateInput( UserInput* pUserInput )
  2688. {
  2689.     if( NULL == m_pInputDeviceManager )
  2690.         return;
  2691.  
  2692.     // Get access to the list of semantically-mapped input devices
  2693.     CInputDeviceManager::DeviceInfo* pDeviceInfos;
  2694.     DWORD dwNumDevices;
  2695.     m_pInputDeviceManager->GetDevices( &pDeviceInfos, &dwNumDevices );
  2696.  
  2697.     // Loop through all devices and check game input
  2698.     for( DWORD i=0; i<dwNumDevices; i++ )
  2699.     {
  2700.         DIDEVICEOBJECTDATA rgdod[10];
  2701.         DWORD   dwItems = 10;
  2702.         HRESULT hr;
  2703.         LPDIRECTINPUTDEVICE8 pdidDevice = pDeviceInfos[i].pdidDevice;
  2704.         InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  2705.  
  2706.         hr = pdidDevice->Acquire();
  2707.         hr = pdidDevice->Poll();
  2708.         hr = pdidDevice->GetDeviceData( sizeof(DIDEVICEOBJECTDATA),
  2709.                                         rgdod, &dwItems, 0 );
  2710.         if( FAILED(hr) )
  2711.             continue;
  2712.  
  2713.         // Get the sematics codes for the game menu
  2714.         for( DWORD j=0; j<dwItems; j++ )
  2715.         {
  2716.             BOOL  bButtonState = (rgdod[j].dwData==0x80) ? TRUE : FALSE;
  2717.             FLOAT fButtonState = (rgdod[j].dwData==0x80) ? 1.0f : 0.0f;
  2718.             FLOAT fAxisState   = (FLOAT)((int)rgdod[j].dwData)/10.0f;
  2719.  
  2720.             switch( rgdod[j].uAppData )
  2721.             {
  2722.                 // Handle semantics for normal game play
  2723.  
  2724.                 // Handle relative axis data
  2725.                 case INPUT_AXIS_LR: 
  2726.                     pInputDeviceState->fAxisRotateLR = fAxisState;
  2727.                     break;
  2728.                 case INPUT_AXIS_UD: 
  2729.                     pInputDeviceState->fAxisMoveUD   = -fAxisState;
  2730.                     break;
  2731.  
  2732.                 // Handle mouse data                
  2733.                 case INPUT_MOUSE_LR:
  2734.                     if( fAxisState > -0.4f && fAxisState < 0.4f )
  2735.                         pInputDeviceState->fAxisRotateLR = 0.0f;
  2736.                     else
  2737.                         pInputDeviceState->fAxisRotateLR =fAxisState;
  2738.                     break;
  2739.                 case INPUT_MOUSE_UD:
  2740.                     if( fAxisState > -0.4f && fAxisState < 0.4f )
  2741.                         pInputDeviceState->fAxisMoveUD   = 0.0f;
  2742.                     else
  2743.                         pInputDeviceState->fAxisMoveUD = -fAxisState;
  2744.                     break;
  2745.  
  2746.                 // Handle buttons separately so the button state data
  2747.                 // doesn't overwrite the axis state data, and handle
  2748.                 // each button separately so they don't overwrite each other
  2749.                 case INPUT_TURNLEFT:      pInputDeviceState->bButtonRotateLeft    = bButtonState; break;
  2750.                 case INPUT_TURNRIGHT:     pInputDeviceState->bButtonRotateRight   = bButtonState; break;
  2751.                 case INPUT_FORWARDTHRUST: pInputDeviceState->bButtonForwardThrust = bButtonState; break;
  2752.                 case INPUT_REVERSETHRUST: pInputDeviceState->bButtonReverseThrust = bButtonState; break;
  2753.                 case INPUT_FIREWEAPONS:   pInputDeviceState->bButtonFireWeapons   = bButtonState; break;
  2754.  
  2755.                 // Handle one-shot buttons
  2756.                 case INPUT_MOUSE_SHIPTYPE:
  2757.                     SwitchModel();
  2758.                     break;
  2759.  
  2760.                 case INPUT_CHANGESHIPTYPE: 
  2761.                     if( bButtonState ) 
  2762.                         SwitchModel();
  2763.                     break;
  2764.  
  2765.                 case INPUT_CHANGEVIEW:    
  2766.                     if( bButtonState ) 
  2767.                         pUserInput->bDoChangeView = TRUE; 
  2768.                     break;
  2769.  
  2770.                 case INPUT_CHANGEWEAPONS: 
  2771.                     if( bButtonState )
  2772.                     {
  2773.                         if( ++m_dwBulletType > 3 )
  2774.                             m_dwBulletType = 0L;
  2775.                     }
  2776.                     break;
  2777.  
  2778.                 case INPUT_START:          
  2779.                     if( bButtonState ) 
  2780.                         m_bPaused = !m_bPaused; 
  2781.                     break;
  2782.  
  2783.                 case INPUT_DISPLAYGAMEMENU:
  2784.                     if( bButtonState )
  2785.                     {
  2786.                         PlaySound( m_pSphereExplodeSound );
  2787.                         m_pCurrentMenu = m_pMainMenu;
  2788.                         m_pInputDeviceManager->SetActionFormat( m_diafBrowser, FALSE );
  2789.                     }
  2790.                     break;
  2791.  
  2792.                 case INPUT_QUITGAME:
  2793.                     if( bButtonState )
  2794.                     {
  2795.                         PlaySound( m_pSphereExplodeSound );
  2796.                         m_pCurrentMenu = m_pQuitMenu;
  2797.                         m_pInputDeviceManager->SetActionFormat( m_diafBrowser, FALSE );
  2798.                     }
  2799.                     break;
  2800.  
  2801.                 // Handle semantics for the game menu
  2802.                 case INPUT_MENU_UD:     pInputDeviceState->fAxisMenuUD = -fAxisState; break;
  2803.                 case INPUT_MENU_UP:     if( bButtonState ) pUserInput->bDoMenuUp     = TRUE; break;
  2804.                 case INPUT_MENU_DOWN:   if( bButtonState ) pUserInput->bDoMenuDown   = TRUE; break;
  2805.                 case INPUT_MENU_SELECT: if( bButtonState ) pUserInput->bDoMenuSelect = TRUE; break;
  2806.                 case INPUT_MENU_QUIT:   if( bButtonState ) pUserInput->bDoMenuQuit   = TRUE; break;
  2807.                 case INPUT_MENU_WHEEL:
  2808.                     if( fAxisState > 0.0f )
  2809.                         pUserInput->bDoMenuUp = TRUE; 
  2810.                     else
  2811.                         pUserInput->bDoMenuDown = TRUE; 
  2812.                     break;
  2813.             }
  2814.         }
  2815.     }
  2816.  
  2817.     pUserInput->bButtonFireWeapons = FALSE; 
  2818.     pUserInput->fAxisRotateLR = 0.0f;
  2819.     pUserInput->fAxisMoveUD   = 0.0f;
  2820.  
  2821.     if( m_pShip->bVisible  )
  2822.     {
  2823.         // Accumulate thrust inputs
  2824.  
  2825.         // Concatinate the data from all the DirectInput devices
  2826.         for( i=0; i<dwNumDevices; i++ )
  2827.         {
  2828.             InputDeviceState* pInputDeviceState = (InputDeviceState*) pDeviceInfos[i].pParam;
  2829.     
  2830.             // Use the axis data that is furthest from zero
  2831.             if( fabs(pInputDeviceState->fAxisRotateLR) > fabs(pUserInput->fAxisRotateLR) )
  2832.                 pUserInput->fAxisRotateLR = pInputDeviceState->fAxisRotateLR;
  2833.  
  2834.             if( fabs(pInputDeviceState->fAxisMoveUD) > fabs(pUserInput->fAxisMoveUD) )
  2835.                 pUserInput->fAxisMoveUD = pInputDeviceState->fAxisMoveUD;
  2836.  
  2837.             // Process the button data 
  2838.             if( pInputDeviceState->bButtonRotateLeft )
  2839.                 pUserInput->fAxisRotateLR = -1.0f;
  2840.             else if( pInputDeviceState->bButtonRotateRight )
  2841.                 pUserInput->fAxisRotateLR = 1.0f;
  2842.  
  2843.             if( pInputDeviceState->bButtonForwardThrust )
  2844.                 pUserInput->fAxisMoveUD = 1.0f;
  2845.             else if( pInputDeviceState->bButtonReverseThrust )
  2846.                 pUserInput->fAxisMoveUD = -1.0f;
  2847.  
  2848.             if( pInputDeviceState->bButtonFireWeapons )
  2849.                 pUserInput->bButtonFireWeapons = TRUE;
  2850.         }
  2851.     }
  2852. }
  2853.  
  2854.  
  2855.  
  2856.  
  2857. //-----------------------------------------------------------------------------
  2858. // Error handling
  2859. //-----------------------------------------------------------------------------
  2860.  
  2861.  
  2862.  
  2863.  
  2864. //-----------------------------------------------------------------------------
  2865. // Name: CleanupAndDisplayError()
  2866. // Desc:
  2867. //-----------------------------------------------------------------------------
  2868. VOID CMyApplication::CleanupAndDisplayError( DWORD dwError )
  2869. {
  2870.     TCHAR* strDbgOut;
  2871.     TCHAR* strMsgBox;
  2872.  
  2873.     // Cleanup the app
  2874.     FinalCleanup();
  2875.  
  2876.     // Make the cursor visible
  2877.     SetCursor( LoadCursor( NULL, IDC_ARROW ) );
  2878.     m_bMouseVisible = TRUE;
  2879.  
  2880.     // Get the appropriate error strings
  2881.     switch( dwError )
  2882.     {
  2883.         case DONUTS3DERR_NODIRECT3D:
  2884.             strDbgOut = _T("Could not create Direct3D\n");
  2885.             strMsgBox = _T("Could not create Direct3D.\n\n")
  2886.                         _T("Please make sure you have the latest DirectX\n")
  2887.                         _T(".dlls installed on your system.");
  2888.             break;
  2889.         case DONUTS3DERR_NOD3DDEVICE:
  2890.             strDbgOut = _T("Could not create a Direct3D device\n");
  2891.             strMsgBox = _T("Could not create a Direct3D device. Your\n")
  2892.                         _T("graphics accelerator is not sufficient to\n")
  2893.                         _T("run this demo, or your desktop is using\n")
  2894.                         _T("a color format that cannot be accelerated by\n")
  2895.                         _T("your graphics card (try 16-bit mode).");
  2896.             break;
  2897.         case DONUTS3DERR_NOTEXTURES:
  2898.             strDbgOut = _T("Could not load textures\n");
  2899.             strMsgBox = _T("Couldn't load game textures.\n\n")
  2900.                         _T("Either your graphics hardware does not have\n")
  2901.                         _T("sufficient resources, or the DirectX SDK was\n")
  2902.                         _T("not properly installed.");
  2903.             break;
  2904.         case DONUTS3DERR_NOGEOMETRY:
  2905.             strDbgOut = _T("Could not load .x models\n");
  2906.             strMsgBox = _T("Couldn't load game geometry.\n\n")
  2907.                         _T("Either your graphics hardware does not have\n")
  2908.                         _T("sufficient resources, or the DirectX SDK was\n")
  2909.                         _T("not properly installed.");
  2910.             break;
  2911.         case DONUTS3DERR_NO3DRESOURCES:
  2912.             strDbgOut = _T("Couldn't load create a d3d object\n");
  2913.             strMsgBox = _T("Couldn't create display objects.\n")
  2914.                         _T("Yourr graphics hardware does not have\n")
  2915.                         _T("sufficient resources to run this app.");
  2916.             break;
  2917.         case DONUTS3DERR_NOINPUT:
  2918.             strDbgOut = _T("Could not create input objects\n");
  2919.             strMsgBox = _T("Could not create input objects.");
  2920.             break;
  2921.     }
  2922.  
  2923.     // Output the error strings
  2924.     OutputDebugString( strDbgOut );
  2925.     MessageBox( m_hWndMain, strMsgBox, _T("Donuts3D"), MB_OK );
  2926. }
  2927.  
  2928.